System V消息队列(3)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Alatebloomer/article/details/81902778

消息队列实现回射客户/服务器

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;
}

缺陷:

可能存在死锁现象,当服务器端收到客户端的请求之后,要给客户端回射数据,此时服务器端处于往消息队列发送消息的状态,如果这时候很多客户端发起了很多的请求,将消息队列堵满,服务器端往消息队列发送消息的状态就阻塞了,而客户端还在等待消息的回射,则产生了死锁。

改进思路:

服务器端在回射的时候利用的是私有的队列,当一个客户端创建的时候同时创建一个私有队列,并且客户端往服务器端发送消息的时候,将私有队列的标识符传给服务器端,以便服务器端能往私有队列填充数据。服务端通过创建子进程为客户端服务。

猜你喜欢

转载自blog.csdn.net/Alatebloomer/article/details/81902778