概述
今天我们来谈一谈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有三种:
- IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
- IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
- 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=%xn",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 :%sn",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=%xn",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:%sn",readBuf.mtext);
msgctl(msgID,IPC_RMID,NULL);
return 0;
}
~
我们看一下运行的结果
可以看到接收端进入阻塞状态,接下来我们运行发送端。
可以看到接收端收到消息,发送端也收到了接收端的回应。
以上就是关于Linux进程间通信–消息队列的介绍,尚有不足之处,请各位大神指正。
salute CLC
最后
以上就是大力皮带为你收集整理的Linux进程间通信--消息队列(Message queuing)的全部内容,希望文章能够帮你解决Linux进程间通信--消息队列(Message queuing)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复