Linux17 --- 消息队列
创始人
2024-01-31 03:43:07
0

一、IPC进程间通信:消息队列

消息队列是在两个进程之间传递二进制块数据的一种简单有效的方式。每个数据块都有一个特定的类型,接收方可以根据类型来有选择地接收数据,而不一定像管道和命名管道那样必须以先进先出的方式接收数据。

Linux消息队列的API都定义在sys/msg.h头文件中,包括4个系统调用:msgget、msgsnd、msgrcv 和 msgctl。

在这里插入图片描述

1、相关系统调用:

1)msgget系统调用 – 创建或获取系统调用

msgget系统调用创建一个消息队列,或者获取一个已有的消息队列
其定义如下:
在这里插入图片描述
和semget系统调用一样,key参数是一个键值,用来标识一个全局唯一的消息队列。msgflg参数的使用和含义与semget系统调用的sem_flags参数相同。
msgget成功时返回一个正整数值,它是消息队列的标识符。msgget失败时返回-1,并设置errno。
如果msgget用于创建消息队列,则与之关联的内核数据结构msqid_ds将被创建并初始化。msqid_ds结构体的定义如下:
在这里插入图片描述

2)msgsnd 系统调用 – 添加到队列

msgsnd系统调用把一条消息添加到消息队列中。
其定义如下:
在这里插入图片描述
msqid 参数是由 msgget 调用返回的消息队列标识符。
msg_ptr 参数指向一个准备发送的消息,消息必须被定义为如下类型:
在这里插入图片描述
其中,mtype成员指定消息的类型,它必须是一个正整数。mtext是消息数据。msg_sz参数是消息的数据部分(mtext)的长度。这个长度可以为0,表示没有消息数据。
msgflg参数控制msgsnd的行为。它通常仅支持IPC_NOWAIT标志,即以非阻塞的方式发送消息。默认情况下,发送消息时如果消息队列满了,则msgsnd将阻塞。若IPCNOWAIT标志被指定,则msgsnd将立即返回并设置errno为EAGAIN。

处于阻塞状态的msgsnd调用可能被如下两种异常情况所中断:
1)消息队列被移除。此时msgsnd调用将立即返回并设置errno为EIDRM。
2)程序接收到信号。此时msgsnd调用将立即返回并设置errno为EINTR。
msgsnd成功时返回0,失败则返回-1并设置errno。msgsnd成功时将修改内核数据结构msqid_ds的部分字段,如下所示:
将msg_qnum 加1。
将msg_lspid 设置为调用进程的PID。
将msg_stime设置为当前的时间。

3)msgrcv 系统调用 – 获取消息

msgrcv系统调用从消息队列中获取消息。
其定义如下:
在这里插入图片描述
msqid参数是由msgget调用返回的消息队列标识符。
msg_ptr参数用于存储接收的消息,msg_sz参数指的是消息数据部分的长度。
msgtype参数指定接收何种类型的消息。我们可以使用如下几种方式来指定消息类型:

msgtype等于0。读取消息队列中的第一个消息。
msgtype大于0。读取消息队列中第一个类型为msgtype的	消息(除非指定了标志MSG_EXCEPT,见后文)。
msgtype小于0。读取消息队列中第一个类型值比msgtype		的绝对值小的消息。参数msgflg 控制msgrcv函数的行为。它	可以是如下一些标志的按位或:
IPC_NOWAIT。如果消息队列中没有消息,则msgrcv调用立即返回并设置errno为ENOMSG。
MSG_ EXCEPT。如果msgtype大于0,则接收消息队列中第一个非 msgtype类型的消息。
MSG NOERROR。如果消息数据部分的长度超过了msg_sz,就将它截断。

处于阻塞状态的msgrcv调用还可能被如下两种异常情况所中断:

消息队列被移除。此时msgrcv调用将立即返回并设置errno为EIDRM。
程序接收到信号。此时msgrcv调用将立即返回并设置errno为 EINTR。

msgrcv成功时返回0,失败则返回-1并设置errno。msgrcv成功时将修改内核数据结构msqid_ds的部分字段,如下所示:

将msg_qnum减1。
将msg_lrpid设置为调用进程的PID。
将msg_rtime设置为当前的时间。

4)msgctl – 控制某些属性

msgctl 系统调用控制消息队列的某些属性。
其定义如下:
在这里插入图片描述
msqid参数是由msgget调用返回的共享内存标识符。command参数指定要执行的命令。msgctl支持的所有命令如表13-4所示。
在这里插入图片描述
在这里插入图片描述
msgctl成功时的返回值取决于command参数,如表13-4所示。msgctl函数失败时返回-1并设置errno。

2、代码使用示例:

1)a.c --创建消息队列,并添加一个消息

#include 
#include 
#include 
#include 
#include //定义消息体
struct mess//由用户自己定义,只需要的一个成员为long type,长整形;代表消息类型。结构体名等都可自定义
{long type;char date[128];
};int main()//创建消息队列,并添加一个消息
{int msgid = msgget((key_t)1235,IPC_CREAT|0600);//创建消息队列,IPC..为标志位,0600为权限if(msgid == -1)//判断是否创建成功{exit(0);}//添加消息//先定义一个结构体变量,用来表示消息struct mess dt;//给消息赋消息类型值dt.type = 1;//这里赋值为一号类型消息strcpy(dt.date,"hello1");//这里直接写入一个消息//将结构体添加到消息队列中msgsnd(msgid,(void *)&dt,128,0);//这里的128是数据部分的大小
}

其中4d3为1235,进程已经结束,但消息队列依旧存在。多次运行不会多次创建消息队列,但会多次写入数据。
在这里插入图片描述

2)b.c – 获取消息队列,并读取一个消息

#include 
#include 
#include 
#include 
#include //定义消息体
struct mess//由用户自己定义,只需要的一个成员为long type,长整形;代表消息类型。结构体名等都可自定义
{long type;char date[128];
};int main()//获取消息队列,并读取一个消息
{int msgid = msgget((key_t)1235,IPC_CREAT|0600);//创建消息队列,IPC..为标志位,0600为权限if(msgid == -1)//判断是否创建成功{exit(0);}//读取消息//先定义一个结构体变量,用来表示消息struct mess dt;//获取消息msgrcv(msgid,(void*)&dt,128,1,0);//这里的128是消息部分的大小,不是结构体的大小printf("read:%s\n",dt.date);}

每运行一次b,其就会从其所获取的消息队列中读取一个相对应信号类型的消息,如果没有,就会阻塞,等待另外进程写入,再读取。

msgrcv(msgid,(void*)&dt,128,1,0);

如果将第四个参数改为0,就回不区分消息类型,就会读取任意类型的消息。发送端不能发送0号类型消息,但接收端可以。

在这里插入图片描述

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...