消息队列可以认为是一个消息列表。线程可以往消息队列中放置消息或者取出消息。每个消息都是一条记录,由发送者赋予一个优先级。一个进程在往一个消息队列中写入消息之前,不需要有某个进程在该队列上等待消息到达(这跟管道和FIFO是相反的)。
消息队列具有随内核的持续性, 也就是说在内核重新启动之前,不管发消息的进程或者取消息的进程是否结束,消息队列是始终存在的。
消息队列有两种,分别是Posix消息队列和System V消息队列, 下面的例程是Posix消息队列的使用。
// 1.c
#include
#include
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
int main(int argc, char* argv[])
{
int flag;
mqd_t mdq;
flag = O_RDWR | O_CREAT;
if (argc < 2) {
printf("Please input mqueue name!\n");
}
// NULL 表示采用默认属性
mdq = mq_open(argv[1], flag, FILE_MODE, NULL);
return 0;
}
以上是一个创建消息队列的例程,使用如下命令进行编译得到可执行文件a.out
gcc -g 1.c -Wall -lrt
执行以下命令,即可得到一个名为temp.1234的消息队列, 这个消息队列保存在/dev/mqueue中
./a.out /temp.1234
[root@localhost IPC]# ll /dev/mqueue/
total 0
-rw-r--r--. 1 root root 80 Nov 9 06:59 temp.1234
注意 消息队列的名字必须以’/'开头,才能创建成功。
删除消息队列使用mq_unlink函数.
// 2.c
#include
#include
int main(int argc, char* argv[])
{
if (argc < 2) {
printf("Please input mqueue name!\n");
}
int ret = mq_unlink(argv[1]);
printf("%d\n", ret);
return 0;
}
编译
gcc -g 2.c -Wall -lrt
执行
./a.out /temp.1234
执行完之后,可以看到刚才创建的消息队列已经被删除了。
[root@localhost IPC]# ll /dev/mqueue/
total 0
每个消息队列有四个属性,mq_getattr函数返回所有这些属性。
struct mq_attr {
long mq_flags;
long mq_maxmsg; //消息队列上最多可以存储的消息数目
long mq_msgsize; //一条消息最多可以容纳多少字节
long mq_curmsgs; //当前队列中存储的消息数量
};
// 3.c
#include
#include
int main(int argc, char* argv[])
{
mqd_t mqd;
struct mq_attr attr;
if (argc < 2) {
printf("Please input mqueue name!\n");
}
mqd = mq_open(argv[1], O_RDONLY);
mq_getattr(mqd, &attr);
printf("max msgs = %ld\nmax bytes/msg = %ld\ncurrently on queue = %ld\n",
attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
mq_close(mqd);
return 0;
}
编译执行,查看我们刚才创建的消息队列的属性
gcc -g 3.c -Wall -lrt
./a.out /temp.1234
max msgs = 10
max bytes/msg = 8192
currently on queue = 0
可以看到我们创建的消息队列最多容纳10条消息,每条消息最多8192字节,当前队列上一条消息也没有。
mq_setattr函数给队列设置属性,但是只使用mq_attr结构中的mq_flags字段以设置或者清除非阻塞标志位, 这个结构的其他三个成员均被忽略。
如果希望设置最大消息数量和每条消息的最大字节数量,需要在创建队列的时候指定。
在前面的例子当中,以默认属性创建的队列所能容纳的最大消息数量是10, 每条消息最多8192个字节。现在,我们尝试以我们自己指定的属性创建队列。
// 4.c
#include
#include
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
struct mq_attr attr;
int main(int argc, char* argv[])
{
int flag;
mqd_t mdq;
flag = O_RDWR | O_CREAT;
if (argc < 2) {
printf("Please input mqueue name!\n");
return -1;
}
attr.mq_maxmsg = 20;
attr.mq_msgsize = 4096;
mdq = mq_open(argv[1], flag, FILE_MODE, &attr);
mq_close(mdq);
return 0;
}
在这个例子当中,我们设置最大的消息数量是20, 每条消息最多4096个字节。
编译运行,并查看一下属性
max msgs = 20
max bytes/msg = 4096
currently on queue = 0
可以看到,这次我们创建了一个不同的消息队列。
这两个函数用于向一个队列添加和取出消息。每个消息有一个优先级, mq_receive总是返回队列中最高优先级的最早消息, 而且该优先级可以随该消息的内容和长度一并返回。
发送
// send
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int priorty;
mqd_t mqd;
if (argc != 4) {
printf("usage: send n" );
return -1;
}
priorty = atoi(argv[3]);
mqd = mq_open(argv[1], O_WRONLY);
int ret = mq_send(mqd, argv[2], strlen(argv[2]), priorty);
if (ret != 0) {
printf("send message error!\n");
}
mq_close(mqd);
return 0;
}
接收
// receive
#include
#include
#include
struct mq_attr attr;
int main(int argc, char* argv[])
{
unsigned int priorty, cnt;
mqd_t mqd;
void* buff;
if (argc != 2) {
printf("usage: mqrece \n");
return -1;
}
mqd = mq_open(argv[1], O_RDONLY);
mq_getattr(mqd, &attr);
printf("size = %ld\n", attr.mq_msgsize);
buff = malloc(attr.mq_msgsize);
cnt = mq_receive(mqd, buff, attr.mq_msgsize, &priorty);
printf("received %d bytes, priority = %u\n", cnt, priorty);
printf("message = %s\n", (char*)buff);
mq_close(mqd);
return 0;
}
消息队列的实现定义了两个限制:
这两个值通常定义在
#include
#include
int main()
{
printf("MQ_OPEN_MAX = %ld\nMQ_PRIO_MAX = %ld\n", sysconf(_SC_MQ_OPEN_MAX), sysconf(_SC_MQ_PRIO_MAX));
return 0;
}
在linux下运行得到的结果是
MQ_OPEN_MAX = -1
MQ_PRIO_MAX = 32768
-1 表示对数量没有限制