消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法。
与管道不同,进程并没有必要提供自己的同步机制,这是消息队列比起管道的一个巨大优点。
坏处在于,与管道类似,在每一个数据块上有一个最大尺寸限制,同时在系统中所有消息队列上的块尺寸上也有一个最大尺寸限制。
消息结构由两种方式来限定。第一,他必须小于系统限制,第二,必须以long int开始,这在接收函数中会用作一个消息类型。当我们在使用消息时,最好是以如下形式来定义我们的消息结构:
struct my_message {
long int message_type;
/* The data you wish to transfer */
}
写端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg
{
long int type;
char buf[BUFSIZ];
};
int main()
{
// 消息队列的创建
// int msgget(key_t key, int msgflg);
// 不同的进程调用此函数,只要用相同的 key 值就能得到同一个消息队列的标识符
// msgflg: 标识函数的行为及消息队列的权限,其取值如下:
// IPC_CREAT:创建消息队列。
// IPC_EXCL: 检测消息队列是否存在。
// 位或权限位:消息队列位或权限位后可以设置消息队列的访问权限,
// 格式和open() 函数的 mode_t 一样,但可执行权限未使用。
int msgid = msgget((key_t)1234, 0666|IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
struct my_msg data;
while(1)
{
printf("Enter: ");
fgets(data.buf, BUFSIZ, stdin);
data.type = 1;
// 将新消息添加到消息队列
// int msgsnd( int msqid, const void *msgp, size_t msgsz, int msgflg);
// msqid: 消息队列的标识符。
// msgp: 待发送消息结构体的地址。
// msgsz: 消息正文的字节数。
// msgflg:函数的控制属性,其取值如下:
// 0:msgsnd() 调用阻塞直到条件满足为止。
// IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。
if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(strncmp(data.buf, "end", 3) == 0)
break;
}
return 0;
}
读端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg
{
long int type;
char buf[BUFSIZ];
};
int main()
{
int msgid = msgget((key_t)1234, 0666|IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error:%d\n", errno);
exit(EXIT_FAILURE);
}
struct my_msg data;
while(1)
{
// 获取消息
// ssize_t msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg );
// 从标识符为 msqid 的消息队列中接收一个消息
// 一旦接收消息成功,则消息在消息队列中被删除
// msqid:消息队列的标识符,代表要从哪个消息列中获取消息。
// msgp: 存放消息结构体的地址。
// msgsz:消息正文的字节数。
// msgtyp:消息的类型。可以有以下几种类型:
// msgtyp = 0:返回队列中的第一个消息。
// msgtyp > 0:返回队列中消息类型为 msgtyp 的消息(常用)。
// msgtyp < 0:返回队列中消息类型值小于或等于 msgtyp 绝对值的消息,
// 如果这种消息有若干个,则取类型值最小的消息。
// msgflg:函数的控制属性。其取值如下:
// 0:msgrcv() 调用阻塞直到接收消息成功为止。
// MSG_NOERROR: 若返回的消息字节数比 nbytes 字节数多,
// 则消息就会截短到 nbytes 字节,且不通知消息发送进程。
// IPC_NOWAIT: 调用进程会立即返回。若没有收到消息则立即返回 -1。
if(msgrcv(msgid, (void*)&data, BUFSIZ, 0, 0) == -1)
{
fprintf(stderr, "msgrcv failed with error %d\n", errno);
exit(EXIT_FAILURE);
}
printf("Receive: %s", data.buf);
if(strncmp(data.buf, "end", 3) == 0)
break;
}
// 消息队列的控制
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
// 对消息队列进行各种控制,如修改消息队列的属性,或删除消息消息队列
// msqid:消息队列的标识符。
// cmd:函数功能的控制。其取值如下:
// IPC_RMID:删除由 msqid 指示的消息队列,将它从系统中删除并破坏相关数据结构。
// IPC_STAT:将 msqid 相关的数据结构中各个元素的当前值存入到由 buf 指向的结构中。
// 相对于,把消息队列的属性备份到 buf 里。
// IPC_SET:将 msqid 相关的数据结构中的元素设置为由 buf 指向的结构中的对应值。
// 相当于,消息队列原来的属性值清空,再由 buf 来替换。
// buf:msqid_ds 数据类型的地址,用来存放或更改消息队列的属性。
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(PCI_RMID) failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
参考
https://blog.youkuaiyun.com/lh2016rocky/article/details/70256844
https://blog.youkuaiyun.com/tennysonsky/article/details/46331643