一步一步创建聊天程序1利用进程和共享内存来创建简易聊天程序

编程

    最近学习了linux关于进程间通信的相关知识,所以决定借助进程和共享内存,并按照生产者消费者模型来创建一个简易聊天程序。下面简单的说一下程序的思路。
    首先是服务端程序,服务端会创建两个进程,进程1负责接收客户端传送过来的消息,并存储起来。进程2负责读取进程1存取的消息。这里使用到了生产者和消费者编程模型,并声明了如下的消息存放结构体。

struct message

{

int target_id;

char buf[100];

};

//消息仓库

struct canku

{

struct message recv_message[10];

int read_pos,write_pos;

}messages;

 

 

可以看到,我在这里强制消息仓库最多只能存放10条消息(其实只能存放9条,和生产者消费者模型有关)。
    生产者和消费者模型:利用read_pos和write_pos来分别标记读取和写入的位置,每次读取和写入后,read_pos或write_pos都会递增1,当read_pos或write_pos到达数组末尾时,就将其重置为0,类似于一个环形链表,可这会出现一个问题:如何判断链表是否为空,或链表是否已经被写满了?
    利用read_pos(消息读取的位置)和write_pos(消息写入的位置)来判断消息仓库是否为空和已满。消息仓库在空和满两种状态时,read_pos与write_pos都相等,这样明显不满足我们的要求。所以,空出一个消息位,来利用如下条件判断消息是否空或满。

  1. 消息为空时

    if((messages_ptr->read_pos)%10==messages_ptr->write_pos)

    {

    //printf("buff is empty

    ");

    shmdt(messages_ptr);

    continue;

    }

     

    即当read_pos和write_pos值相等时,则表示消息仓库为空状态。

  2. 消息仓库已满时

    if((messages_ptr->write_pos+1)%10==messages_ptr->read_pos)

    {

    shmdt(messages_ptr);

    continue;

    }

     

     

    即当write_pos下一个位置为read_pos时,此时仓库已满。可以看到,该消息空间无法存储数据,被浪费了。这样的方法就解决了如何判断消息仓库空状态和满状态的问题,但是却浪费了一个消息空间。

    同时,我们还借助于共享内存,将消息仓库映射到共享内存上,这样,进程1和进程2都可以访问消息仓库。

    客户端比服务端简单,我创建了一个子进程用来读取服务端转发的其他客户端发来的消息。父进程则用来读取客户输入,将消息发送到服务器。

    代码如下:
  服务端:

  

#include <stdio.h>

#include <pthread.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <errno.h>

#define MAX_LISTEN 10

struct message

{

int target_id;

char buf[100];

};

//消息仓库

struct canku

{

struct message recv_message[10];

int read_pos,write_pos;

}messages;

//messages初始化

void init()

{

messages.read_pos=0;

messages.write_pos=0;

}

//messages销毁

void finish()

{

messages.read_pos=0;

messages.write_pos=0;

}

int sd;

int main()

{

init();

struct sockaddr_in server_ip,customer_ip;

int err;

sd=socket(AF_INET,SOCK_STREAM,0);

if(sd==-1)

{

printf("socket failed

");

close(sd);

return -1;

}

//server_ip初始化

server_ip.sin_family=AF_INET;

server_ip.sin_port=htons(5678);

server_ip.sin_addr.s_addr=htonl(INADDR_ANY);

memset(server_ip.sin_zero,0,8);

err=bind(sd,(struct sockaddr *)(&server_ip),sizeof(struct sockaddr));

if(err==-1)

{

printf("bind failed

");

close(sd);

return -1;

}

err=listen(sd,MAX_LISTEN);

if(err==-1)

{

printf("listen failed

");

close(sd);

return -1;

}

int length=sizeof(customer_ip);

//初始化共享变量,大小等于canku by luke

int shmid=shmget(IPC_PRIVATE,sizeof(struct canku),IPC_CREAT|0777);

if(shmid<0)

{

printf("shmget failed

");

return -1;;

}

struct canku * messages_ptr=&messages;

while(1)

{

int temp_cd=accept(sd,(struct sockaddr *)(&customer_ip),&length);

if(temp_cd==-1)

{

printf("accept failed,ereno: %d

",temp_cd);

close(sd);

return -1;

}

printf("user %d online

",temp_cd);

pid_t pid=fork();

if(pid==0)//子进程 by luke

{

while(1)

{

messages_ptr=shmat(shmid,NULL,0);

if((messages_ptr->write_pos+1)%10==messages_ptr->read_pos)

{

shmdt(messages_ptr);

continue;

}

struct message temp_message;

err=recv(temp_cd,&temp_message,sizeof(struct message),0);

//err=read(temp_cd,&(recv_message[count-1]),sizeof(struct message));

if(err!=-1)

{

messages_ptr->recv_message[messages_ptr->write_pos].target_id=temp_message.target_id;

strcpy(messages_ptr->recv_message[messages_ptr->write_pos].buf,temp_message.buf);

printf("recv: read_pos: %d, write_pos: %d, target_id: %d, buf: %s

",messages_ptr->read_pos,messages_ptr->write_pos+1,messages_ptr->recv_message[messages_ptr->write_pos].target_id,messages_ptr->recv_message[messages_ptr->write_pos].buf);

messages_ptr->write_pos++;

if(messages_ptr->write_pos==9)

messages_ptr->write_pos=0;

}

shmdt(messages_ptr);

}

}

//防止主线程被while住,无法接受新的连接请求。

pid_t pid1=fork();

if(pid1==0)

{

while(1)

{

messages_ptr=shmat(shmid,NULL,0);

if((messages_ptr->read_pos)%10==messages_ptr->write_pos)

{

//printf("buff is empty

");

shmdt(messages_ptr);

continue;

}

//strcpy(messages_ptr->recv_message[messages_ptr->read_pos].buf,"hello");

err=send(messages_ptr->recv_message[messages_ptr->read_pos].target_id,messages_ptr->recv_message[messages_ptr->read_pos].buf,100,0);

if(err==-1)

{

//printf("send failed

");

}

else

{

printf("send: read_pos: %d, write_pos: %d ,message.target_id: %d, message.buf: %s

",messages_ptr->read_pos+1,messages_ptr->write_pos,messages_ptr->recv_message[messages_ptr->read_pos].target_id,messages_ptr->recv_message[messages_ptr->read_pos].buf);

messages_ptr->read_pos++;

if(messages_ptr->read_pos==9)

messages_ptr->read_pos=0;

}

shmdt(messages_ptr);

}

}

}

close(sd);

shmctl(shmid,IPC_RMID,NULL);

finish();

return0;

}

客户端:

#include <stdio.h>

#include <pthread.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

struct message

{

int target_id;

char buf[100];

};

int sd;

struct message send_message;

void * read_message(void * argv)

{

while(1)

{

//读服务器发来的消息

char revBuf[100];

read(sd,revBuf,100);

printf("recevice from server: %s",revBuf);

}

}

void * write_message(void * argv)

{

while(1)

{

printf("input message:

");

memset(send_message.buf,0,128);

send_message.target_id=-1;

scanf("%d %s",&send_message.target_id,send_message.buf);

write(sd,&send_message,sizeof(send_message));

sleep(3);

}

}

int main()

{

struct sockaddr_in server_ip,customer_ip;

int err;

sd=socket(AF_INET,SOCK_STREAM,0);

if(sd==-1)

{

printf("socket failed

");

close(sd);

return -1;

}

//server_ip初始化

server_ip.sin_family=AF_INET;

server_ip.sin_port=htons(5678);

server_ip.sin_addr.s_addr=htonl(INADDR_ANY);

//err=inet_aton("115.157.201.179",&server_ip.sin_addr.s_addr);

memset(server_ip.sin_zero,0,8);

err=connect(sd,(struct sockaddr *)(&server_ip),sizeof(server_ip));

if(err==-1)

{

printf("connect failed

");

close(sd);

return -1;

}

pid_t pid=fork();

if(pid==0)

{

while(1)

{

//读服务器发来的消息

//printf("read message:

");

char revBuf[100];

recv(sd,revBuf,100,0);

//read(sd,revBuf,100);

printf("recevice from server: %s

",revBuf);

}

}

while(1)

{

printf("input message:

");

memset(send_message.buf,0,128);

send_message.target_id=-1;

scanf("%d %s",&send_message.target_id,send_message.buf);

if(send_message.target_id!=-1&&(strcmp(send_message.buf,"")!=0))

{

err=send(sd,&send_message,sizeof(send_message),0);

if(err==-1)

{

printf("send failed

");

}

//write(sd,&send_message,sizeof(send_message));

send_message.target_id=-1;

memset(send_message.buf,0,sizeof(send_message.buf));

}

sleep(3);

}

close(sd);

return0;

}

 

以上是 一步一步创建聊天程序1利用进程和共享内存来创建简易聊天程序 的全部内容, 来源链接: utcz.com/z/511036.html

回到顶部