Linux进程间通信--消息队列(Message queuing)

今天我们来谈一谈Linux进程间通信的方式之一消息队列
我们先来看看关于消息队列的定义:
1.消息队列是消息的链表,存放在内核中并由消息队列标识符表示。

2.消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型。但是同管道类似,它有一个不足就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数(MSGMNB),系统上消息队列的总数上限(MSGMNI)。可以用cat /proc/sys/kernel/msgmax查看具体的数,据。

我用自己的话总结一下就是这是一个类似管道的通信方式,但是可以双向通信,而且消息队列不会随进程执行完毕而消失,消息队列的生命周期随内核,我们可以手动关闭。

简单概述一下应用场景:
接收端发送端拥有相同的消息队列的ID号,当接收端执行程序后进入阻塞状态,等待服务端发送消息,发送端发送消息进入消息队列后,接收端打开阻塞,并向消息队列发送我已经收到消息的字符串,发送端再从消息队列中接收

介绍一下用到的api:
1.msgget
原型是

int msgget(key_t key, int msgflag);

第一个参数是消息队列的ID号,第二个是权限,一般我们用若无则创建+可读可写方式
比如

int msgID=msgget(key,IPC_CREAT|0777);

其中key的值我们通过ftok这api得到
2.ftok
key_t ftok( char * fname, int id )
fname就时你指定的文件名,id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
代码示例:

key_t key;
key =ftok(".",'1');

3.msgsnd
原型:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

第一个参数是ID号,第二个是你要发送的东西,第三个是发多少大小,第四个默认为0.
返回值,成功为0,失败为-1
示例:

msgsnd(msgID,&sendBuf,strlen(sendBuf.mtext),0);

4.msgrcv
原型:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 

第三个参数就是消息队列结构体里面的mtype其余与msgsnd相同
示例:

msgrcv(msgID,&readBuf,sizeof(readBuf.mtext),888,0);

5.msgctl
原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
第一个参数ID号,第二个执行什么命令,第三个我们一般用NULL
cmd有三种:

  1. IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
  2. IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
  3. IPC_RMID 删除消息队列

示例:

msgctl(msgID,IPC_RMID,NULL);

以上就是关于消息队列api的介绍

接下来我们来看一下代码
首先是接收端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>

struct msgbuf{
        long mtype;
        char mtext[128];

};

int main()
{
        struct msgbuf readBuf;

        key_t key;
        key =ftok(".",'1');
        printf("key=%x\n",key);

        int msgID=msgget(key,IPC_CREAT|0777);
        if(msgID == -1){
                printf("get mq  error!\n");
        }

        msgrcv(msgID,&readBuf,sizeof(readBuf.mtext),888,0);
        printf("read from mq :%s\n",readBuf.mtext);

        struct msgbuf sendBuf = {900,"I'm get message"};
        msgsnd(msgID,&sendBuf,strlen(sendBuf.mtext),0);

        msgctl(msgID,IPC_RMID,NULL);//删除消息队列

return 0;
}
~                  

然后是发送端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>

struct msgbuf{
        long mtype;
        char mtext[128];

};

int main()
{
        key_t key;
        key =ftok(".",'1');
        printf("key=%x\n",key);

        struct msgbuf sendBuf = {888,"this is message from mq"};

        int msgID=msgget(key,IPC_CREAT|0777);
        if(msgID == -1){
                printf("get mq  error!\n");
        }

        msgsnd(msgID,&sendBuf,strlen(sendBuf.mtext),0);

        struct msgbuf readBuf;
        msgrcv(msgID,&readBuf,sizeof(readBuf.mtext),900,0);
        printf("read from mq return:%s\n",readBuf.mtext);

        msgctl(msgID,IPC_RMID,NULL);

return 0;
}
~                     

我们看一下运行的结果
在这里插入图片描述
可以看到接收端进入阻塞状态,接下来我们运行发送端。
在这里插入图片描述在这里插入图片描述

可以看到接收端收到消息,发送端也收到了接收端的回应。

以上就是关于Linux进程间通信–消息队列的介绍,尚有不足之处,请各位大神指正。

salute CLC

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值