一、消息队列原理
上图为消息队列原理示意图
我们创建一个消息队列之后,可以向消息队列中添加消息,也可以获取消息,其存放数据的地方在内存中。
在添加消息的时候,可以指定消息的类型(前面的1 、2 就是消息的类型)来决定被谁接收,在接收消息的时候,也可以根据其类型接收,例如:要接收2号类型的消息,就不会接收到1号类型的消息。
和管道相比,管道是一个字节流式的(写入什么就读取什么),而消息队列是一个结构体,类型更加丰富,我们所需要的东西都可以自己去定义。
二、消息队列函数介绍
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msqflg);
/*
msgget()创建或者获取一个消息队列
msgget()成功返回消息队列 ID,失败返回-1
msqflg: IPC_CREAT
*/
int msgsnd(int msqid, const void *msqp, size_t msqsz, int msqflg);
/*
msgsnd()发送一条消息,消息结构为:
struct msgbuf
{
long mtype; // 消息类型, 必须大于 0
char mtext[1]; // 消息数据
};
msgsnd()成功返回 0, 失败返回-1
msqsz: 指定 mtext 中有效数据的长度
msqflg:一般设置为 0 可以设置 IPC_NOWAIT
*/
ssize_t msgrcv(int msqid, void *msgp, size_t msqsz, long msqtyp, int msqflg);
/*
msgrcv()接收一条消息
msgrcv()成功返回 mtext 中接收到的数据长度, 失败返回-1
msqtyp: 指定接收的消息类型,类型可以为 0
msqflg: 一般设置为 0 可以设置 IPC_NOWAIT
*/
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
/*
msgctl()控制消息队列
msgctl()成功返回 0,失败返回-1
cmd: IPC_RMID
*/
三、代码示例
示例代码1:进程 a 发送一条消息,进程 b 读取消息。
a.c 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/msg.h>
typedef struct msgdata//自定义消息队列结构体
{
long mtype;
char mtext[128];
}MsgData;
int main()
{
int msgid = msgget((key_t)1234, 0664 | IPC_CREAT);//创建消息队列
assert(msgid != -1);
MsgData data;
memset(&data, 0, sizeof(data));//将结构体清空
data.mtype = 1;//消息类型为 1
strcpy(data.mtext, "hello");
msgsnd(msgid, &data, 128, 0);//发送数据到消息队列
exit(0);
}
b.c 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/msg.h>
typedef struct msgdata//自定义消息队列结构体
{
long mtype;
char mtext[128];
}MsgData;
int main()
{
int msgid = msgget((key_t)1234, 0664 | IPC_CREAT);//创建消息队列
assert(msgid != -1);
MsgData data;
memset(&data, 0, sizeof(data));//将结构体清空
msgrcv(msgid, &data, 128, 1, 0);//接收消息队列 1号消息
printf("data.type: %d\n", data.mtype);
printf("data.text: %s\n", data.mtext);
msgctl(msgid, IPC_RMID, NULL);
exit(0);
}