linux进程间通信:消息队列实现双端通信

双端通信描述

利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发。
同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无法再次写入)让消息队列的实现过程只能如下:

  • 客户端1的父进程用来处理类型1的消息写,子进程处理类型2的消息读
  • 客户端2的父进程处理类型2的消息写,子进程处理类型1的消息读

实现

客户端1 client1.c

#include
#include 
#include 
#include 
#include 
#include 
#include 

#define MSG_TYPE1 1
#define MSG_TYPE2 2 

struct msgbuf
{
        long mtype;
        char mtext[100];
};

int main()
{
	//当多用户的时候通过指定文件以及设置id来获取唯一的key标识
    //key_t key = ftok(".",100);
    key_t key = 12345; //个人使用的时候可以直接指定key
    
	
	//创建msg_qid的对象
    int msg_qid = msgget(key, IPC_CREAT | 0666);
    struct msgbuf msg1,msg2;

    int ret;
    char send_buf[100],rcv_buf[100];

    ret = fork();
    if ( -1 == ret ) {
        printf("fork failed! \n");
        _exit(-1);
    }
    //子进程处理消息1的写
    else if (ret == 0) {
        while(1) {
            memset(&msg1, 0 , sizeof(msg1));
            
            //初始化消息类型以及消息内容
            scanf("%s",msg1.mtext);
            msg1.mtype = MSG_TYPE1;

            //发送消息到消息标识的msg_qid IPC 对象中
           /* if( -1 == msgsnd(msg_qid,(void *)&msg1,strlen(msg1.mtext),0)) {
                printf("send msg1 failed\n");
                _exit(-1);
            }*/

            msgsnd(msg_qid,(void *)&msg1,strlen(msg1.mtext),0);
        }
    }
    //父进程处理消息2的读
    else {
        while(1) { 
            memset(&msg2, 0, sizeof(msg2));
			//获取消息大小为sizeof(msg2.mtext)
            if (-1 == msgrcv(msg_qid,(void*)&msg2,sizeof(msg2.mtext),MSG_TYPE2,0)){
                printf("receive msg2 failed\n");
                _exit(-1);
            } 
            printf("client1:%s\n",msg2.mtext);
        }
    }
    msgctl(msg_qid,IPC_RMID,NULL);

    return 0;
}

客户端2 client2.c

#include
#include 
#include 
#include 
#include 
#include 
#include 

#define MSG_TYPE1 1
#define MSG_TYPE2 2 

struct msgbuf
{
        long mtype;
        char mtext[100];
};

int main()
{
	//当多用户的时候通过指定文件以及设置id来获取唯一的key标识
    //key_t key = ftok(".",100);
    key_t key = 12345; //个人使用的时候可以直接指定key
    
	
	//创建msg_qid的对象
    int msg_qid = msgget(key, IPC_CREAT | 0666);
    struct msgbuf msg1,msg2;

    int ret;

    ret = fork();
    if ( -1 == ret ) {
        printf("fork failed! \n");
        _exit(-1);
    }
    else if (ret == 0) {
        while(1) {
            memset(&msg1, 0 , sizeof(msg1));
            
            //初始化消息类型以及消息内容
            scanf("%s",msg1.mtext);
            msg1.mtype = MSG_TYPE2;

            //发送消息到消息标识的msg_qid IPC 对象中
            /*if( -1 == msgsnd(msg_qid,(void *)&msg1,strlen(msg1.mtext),0)) {
                printf("send msg1 failed\n");
                _exit(-1);
            }*/
            msgsnd(msg_qid,&msg1,100,0);
        }
    }
    else {
        while(1) { 
            memset(&msg2, 0, sizeof(msg2));

            if (-1 == msgrcv(msg_qid,(void*)&msg2,sizeof(msg2.mtext),MSG_TYPE1,0)){
                printf("receive msg2 failed\n");
                _exit(-1);
            } 
            printf("client2:%s\n",msg2.mtext);
        }
    }
    msgctl(msg_qid,IPC_RMID,NULL);

    return 0;
}

编译运行输出如下:
在这里插入图片描述

消息队列相关命令
ipcs -q 查看系统消息队列
ipcrm -q msqid 按照消息标识删除当前用户下的消息队列
ipcmk -Q创建消息队列

消息队列相比于fifo的主要差异

差异:

  • 消息的改变,每个消息都有自己的身份标识
  • 内核提供访问消息结构的接口,并且提供结构来动态修改消息结构

共同点:
消息的接受和发送都是阻塞读和阻塞写,即需要将写的内容读出,否则下次发送会阻塞写

你可能感兴趣的:(#,编程语言C,#,linux操作系统:进程管理,编程语言)