参考网上资源:https://www.bookstack.cn/read/linuxapi/docs-msgsnd-msgrcv.md
消息队列提供了一种从一个进程向另外一个进程发送一个数据块的方法。
消息队列每个消息的最大长度有限制,每个消息队列总字节数有限制,系统的消息队列有限制;
查看每个消息的最大长度:
cat /proc/sys/kernel/msgmax
查看每个消息队列总的字节数:
cat /proc/sys/kernel/msgmnb
查看消息队列的总数上限:
cat /proc/sys/kernel/msgmni
通过root用户修改/etc/sysctl.conf中的配置可调整上述参数的大小(如果本身/etc/sysctl.conf中没有相应的配置信息,则可以新增):
kernel.msgmni=65536
kernel.msgmax=81920
kernel.msgmnb=4194304
修改后执行下面的命令生效:
/sbin/sysctl -p
ipcs -q :查看消息队列
ipcs -pq :查看消息队列对应的用户、发送和接收进程pid
ipcs -q -i msgid :查看该msgid的消息队列的详细情况
ipcrm -Q key:删除消息队列
消息队列数据结构
消息的链式队列。
重要的数据结构
msqid_ds 代码如下(示例):
//位置/usr/include/linux/msg.h
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* 指向消息头 */
struct msg *msg_last; /* 指向消息尾 */
__kernel_time_t msg_stime; /* 最近msgsnd(发送消息)时间 */
__kernel_time_t msg_rtime; /* 最近msgrcv(接收消息)时间 */
__kernel_time_t msg_ctime; /* 最近修改时间 */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* 当前队列的字节数 */
unsigned short msg_qnum; /* 当前队列中消息个数 */
unsigned short msg_qbytes; /* 队列最大字节数 */
__kernel_ipc_pid_t msg_lspid; /* 最近msgsnd的pid */
__kernel_ipc_pid_t msg_lrpid; /* 最近receive的pid */
};
每一个IPC机制都有一个ID,只有ID值相同才能传递数据。它的类型是key_t(int),但是设置任意数字为key值有违软件设计的思想。所以Linux提供了函数ftok来创建key值,以文件为参数,提高了与文件的关联度。
创建消息队列。如果把消息队列看做一个文件的话,那么该函数就相当于open。
#include
#include
#include
int msgget(key_t key, int msgflg);
参数
a) 第一个参数是key值。
b) 第二个参数的地位用来确定消息队列的访问权限。可以附加参数:
比如:msgid=msgget(key,0666|IPC_CREAT)
IPC_CREAT | 如果key不存在,则创建(类似open函数的O_CREAT) |
---|---|
IPC_EXCL | 如果key存在,则返回失败(类似open函数的O_EXCL) |
IPC_NOWAIT | 如果需要等待,则直接返回错误 |
返回值
成功执行时,返回消息队列标识符。失败返回-1,errno被设为以下的某个值
EACCES
:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权能EEXIST
:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志ENOENT
:key指定的消息队列不存在同时msgflg中不指定IPC_CREAT标志ENOMEM
:需要建立消息队列,但内存不足ENOSPC
:需要建立消息队列,但已达到系统的限制该函数用来对消息队列的基本属性进行控制、修改。
#include
#include
#include
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数
a) msqid为消息队列标识符。
b) cmd为执行的控制命令(在ipc.h中定义):
c) buf
IPC_RMID
删除消息队列。从系统中删除给消息队列以及仍在该队列上的所有数据,这种删除立即生效。
仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错,并返回EIDRM。
此命令只能由如下两种进程执行:
IPC_SET
设置消息队列的属性。按照buf指向的结构中的值,来设置此队列的msqid_id结构。
该命令的执行特权与上一个相同。
IPC_STAT
读取消息队列的属性。取得此队列的msqid_ds结构,并存放在buf*中。
IPC_INFO
读取消息队列基本情况。
这是一对函数,用于消息队列的发送和接收
msgsnd函数:用于将新的消息添加到消息队列的尾端。
msgrcv函数:用于从消息队列中读取msqid指定的消息
#include
#include
#include
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
参数
(1) msgsnd
a) msqid:消息队列标识符(由msgget生成)
b) msgp:指向用户自定义的缓冲区(msgp)
c) msgsz:接收信息的大小。范围在0~系统对消息队列的限制值
d) msgflg:指定在达到系统为消息队列限定的界限时应采取的操作。
(2) msgrcv
a) msqid:消息队列标识符
b) msgp:指向用户自定义的缓冲区(msgp)
c) msgsz:如果收到的消息大于msgsz,并且msgflg&MSG_NOERROR为真,则将该消息截至msgsz字节,并且不发送截断提示
d) msgtyp:用于指定请求的消息类型:
e) msgflg:用于指定所需类型的消息不再队列上时的将要采取的操作:
返回值
毋庸置疑,成功0,失败-1。
其他要注意的是,消息队列数据结构(msqid_ds类型)成员的变化:
(1) msgsnd
成功时:
(2) msgrcv
成功时:
该类型需要自己在编程时定义,用于存储消息的内容。
下面给出一个范例,注意,里面的名称随意。
消息类型必须要有,且不为0
struct msgbuf{
long mtype; //消息类型
char mtext[1];//数组大小编程时自己指定
};