消息队列相关的系统参数:
(1)
# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7744
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200 <--- The maximum number of bytes in POSIX message queues 这个选项仅对 POSIX 消息队列有影响。
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7744
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
(2)
kernel.msgmnb = 65536 //队列中 所有消息 最大字节总数
kernel.msgmni = 16 //系统管理的最多的 消息队列数
kernel.msgmax = 65536 //消息队列可以发送的 单个消息 的最大字节数
【重要】:
多进程读写消息队列不需要考虑进程同步,内部有同步保护, 这点是比共享内存要方便的地方。
测试:
struct MY_MSG
{
long type;
char msg[1024];
};
该结构MY_MSG尺寸为 4+1024=1028字节
启动两个进程msg_snd.bin,执行 msgsnd(msgid, (struct msgbuf*)&oMY_MSG, sizeof(MY_MSG), 0);
通过ipcs可以看到该消息队列中有2个消息,总大小为 2056字节
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 2056 2
即使关闭进程msg_snd.bin,消息队列中的数据会一直保存,除非有其他进程主动接收或者重启系统。
启动进程msg_rcv.bin,执行 msgrcv(msgid, (struct msgbuf*)&rcv, sizeof(MY_MSG), 100, 0);
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 1028 1
消息队列中的1个消息被读取。
异常测试1:msgsnd 发送的消息尺寸和实际大小不符
启动进程msg_snd.bin, 执行msgsnd(msgid, (struct msgbuf*)&oMY_MSG, sizeof(long), 0);
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 4 1
启动进程msg_rcv.bin,执行 msgrcv(msgid, (struct msgbuf*)&rcv, sizeof(MY_MSG), 100, 0);
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 0 0
获取该消息,但是该消息只有4字节,MY_MSG.msg没有内容
异常测试2:msgsnd 发送的消息尺寸和实际大小不符
启动进程msg_snd.bin, 执行msgsnd(msgid, (struct msgbuf*)&oMY_MSG, sizeof(MY_MSG), 0);
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 1028 1
启动进程msg_rcv.bin,执行 msgrcv(msgid, (struct msgbuf*)&rcv, sizeof(long), 100, 0);
执行失败, 报错如下:
rcv msg failed. nRet: =-1
msgrcv failed. errno:7, errmsg:Argument list too long
再启动进程msg_snd.bin, 执行msgsnd(msgid, (struct msgbuf*)&oMY_MSG, sizeof(long), 0);
ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 1032 2
再次启动进程msg_rcv.bin,执行 msgrcv(msgid, (struct msgbuf*)&rcv, sizeof(long), 100, 0);
执行依然失败, 报错如下:
rcv msg failed. nRet: =-1
msgrcv failed. errno:7, errmsg:Argument list too long
【总结】:
(1)消息队列中的消息是FIFO的模式, msgrcv总是获取最前面的消息。
(2)msgrcv 获取的消息尺寸一定要大于等于消息队列中的消息尺寸,否则会报错 "msgrcv failed. errno:7, errmsg:Argument list too long",
除非 msgrcv flag设置MSG_NOERROR选项, 获取部分数据, 并且将该消息移除消息队列。 msgrcv(msgid, (struct msgbuf*)&rcv, 4, 100, MSG_NOERROR );
异常测试3:修改系统参数,创建消息队列失败
# sysctl -a |grep msg
kernel.msgmnb = 65536
kernel.msgmni = 16 //消息队列个数
kernel.msgmax = 65536
# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 0 0
0x11223344 32769 root 666 0 0
0x11223366 65538 root 666 4 1
# sysctl -w kernel.msgmni=2 <---- 修改消息队列
# ipcs -q <---- 原来已经建立好的消息队列保持不变
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223355 0 root 666 0 0
0x11223344 32769 root 666 0 0
0x11223366 65538 root 666 4 1
./msg_snd.bin <----- 新建消息队列报错
create ipc msg failed. msgid-1
msgget failed. errno:28, errmsg:No space left on device
测试4:在多线程环境下使用消息队列
单进程启动2个线程组。
一个线程组只有1个线程, 负责向消息队列中插入100个消息
#ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x11223388 32768 root 666 1490 100
另一个线程组包含5个线程,负责从消息队列中读取消息,通过测试发现多线程获取是互斥的。
每个线程各20个消息。