消息队列实现回射客户/服务器
server进程接收时, 指定msgtyp为1, 从队首不断接收消息
server进程发送时, 将mtype指定为接收到的client进程的pid
client进程发送的时候, mtype指定为自己进程的pid
client进程接收时, 需要将msgtyp指定为自己进程的pid, 只接收消息类型为自己pid的消息;
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
#define MSGMAX 8192
//消息结构参考格式
struct msgbuf
{
long mtype;
char mtext[MSGMAX];
};
//不停地从各个客户端接收类型为1的消息
//其中消息的前4个字节是pid
void echo_srv(int msgid)
{
int n;
//定义一条消息
struct msgbuf msg;
memset(&msg,0,sizeof(msg));
while(1)
{
//接收的消息类型是1,并且以阻塞的方式接收
if((n=msgrcv(msgid,&msg,MSGMAX,1,0))<0)
ERR_EXIT("msgsnd");
//一旦接收到消息,需要将数据部分解析出来
int pid;
//把一个char数组前4个字节作为int输出
//前四个字节保存客户端进程号码
pid=*((int*)msg.mtext);
fputs(msg.mtext+4,stdout); //打印出真正的消息
msg.mtype=pid; //消息类型
msgsnd(msgid,&msg,n,0);
}
}
int main(int argc,char *argv[])
{
int msgid;
//由服务器端创建一个众所周知的消息队列
msgid=msgget(1234,IPC_CREAT | 0666);
if(msgid==-1)
ERR_EXIT("msgget");
//调用回射服务的程序
echo_srv(msgid);
return 0;
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
#define MSGMAX 8192
//消息结构参考格式
struct msgbuf
{
long mtype;
char mtext[MSGMAX];
};
void echo_cli(int msgid)
{
int n;
int pid;
pid=getpid();
struct msgbuf msg;
memset(&msg,0,sizeof(msg));
//把一个char数组前4个字节为pid
*((int *)msg.mtext)=pid;
//消息的类型
msg.mtype=1;
//不停从键盘上获取一行数据
while(fgets(msg.mtext+4,MSGMAX,stdin)!=NULL) //从第四个字节之后接受消息
{
if(msgsnd(msgid,&msg,4+strlen(msg.mtext+4),0)<0)
ERR_EXIT("msgsnd");
if((n=msgrcv(msgid,&msg,MSGMAX,pid,0))<0) //接收消息
ERR_EXIT("msgsnd");
fputs(msg.mtext+4,stdout);
memset(msg.mtext+4,0,MSGMAX-4);
}
}
int main(int argc,char *argv[])
{
int msgid;
//先打开消息队列,要往消息队列中发送数据
msgid=msgget(1234,0);
if(msgid==-1)
ERR_EXIT("msgget");
echo_cli(msgid);
return 0;
}
缺陷:
可能存在死锁现象,当服务器端收到客户端的请求之后,要给客户端回射数据,此时服务器端处于往消息队列发送消息的状态,如果这时候很多客户端发起了很多的请求,将消息队列堵满,服务器端往消息队列发送消息的状态就阻塞了,而客户端还在等待消息的回射,则产生了死锁。
改进思路:
服务器端在回射的时候利用的是私有的队列,当一个客户端创建的时候同时创建一个私有队列,并且客户端往服务器端发送消息的时候,将私有队列的标识符传给服务器端,以便服务器端能往私有队列填充数据。服务端通过创建子进程为客户端服务。