消息队列
**消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。**用户进程可以向消息队列添加消息,也可以向消息队列读取消息。
消息队列克服了管道只能承载无格式字节流以及缓冲区大小受限等缺点。
其优势是对每个消息指定特定的消息类型,接收的时候可以根据自定义条件接收特定类型的消息,而不一定像管道那样必须以先进先出的方式接收数据。
消息数据由结构体组成
struct msgbuf {
long msg_type; // 信息类型
char msg[size_t]; // 保存信息的数组
};
函数:
1、必备头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
2、创建消息队列
int msgget(key_t key, int msgflg);
- key是一个键值,用来标识一个全局唯一的消息队列,一般使用十六进制数表示
- msgflg表示所需要的操作和权限,可以用来控制和创建一个消息队列
IPC_CREAT
IPC_EXCL
IPC_CREAT | IPC_EXCL
- 返回值:
调用成功:返回消息队列的标识号
调用失败:返回 -1
3、向消息队列中写入消息
int msgsnd(int msgid, const void *ptr, size_t nbytes, int flag);
- msgid表示消息队列的标识号
- ptr表示消息结构体的指针(存放数据的结构体指针)
- nbytes表示消息结构体中字符数组的大小
- flag表示消息队列选择的模式
0 -- 当消息队列满时,msgsnd会阻塞进程,直到消息能写进消息队列中或者消息队列被删除
IPC_NOWAIT -- 不会阻塞进程,会立即返回 EAGAIN
- 返回值:
调用成功:返回 0
调用失败:返回 -1
4、从消息队列中读取信息
size_t msgrcv(int msgid, void *ptr, size_t nbytes, long type, int flag);
- msgid表示消息队列的标识号
- ptr表示消息结构体的指针(存放数据的结构体指针)
- nbytes表示消息结构体中字符数组的大小
- type表示根据类型读取消息队列中的数据
0 -- 返回队列中的第一个消息
>0 -- 返回队列中消息类型为 type 的第一个消息
<0 -- 返回队列中消息类型值小于等于 type绝对值的消息,如果这种消息有好多个,则取类型最小的消息
- flag:
0 -- 阻塞进程,直到成功读取到信息为止
IPC_NOWAIT -- 如果读取不到信息立即返回,错误码为 ENOMSG
- 返回值:
调用成功:返回消息数据的长度
调用失败:返回 -1
5、删除消息队列
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
- msgid表示消息队列的标识号
- cmd:
IPC_RMID
- buf设置为 NULL
举例
// write_msg.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf {
long int mymsg_type;
char msg[100];
} msg;
int main() {
// 创建消息队列
int msgid = msgget((key_t)0x5005, IPC_CREAT | 0666);
if (msgid == -1) {
perror("msgget!");
}
// 提前准备数据,并拷贝至消息队列结构体中
msg.mymsg_type = 1;
char buf[100] = "Hello world!\n This is my show!";
memcpy(msg.msg, buf, strlen(buf));
// 将消息发送到消息队列中
int res = msgsnd(msgid, &msg, 100, 0);
if (res == -1) {
perror("msgsnd!");
}
return 0;
}
// read_msg.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf {
long int mymsg_type;
char msg[100];
} msg;
int main() {
// 创建消息队列
int msgid = msgget((key_t)0x5005, IPC_CREAT | 0666);
if (msgid == -1) {
perror("msgget!");
}
// 读取消息队列中的数据
int res = msgrcv(msgid, &msg, 100, 1, IPC_NOWAIT); // 非阻塞读取
if (res == -1) {
perror("msgsnd!");
}
// 打印数据
printf("%s\n", msg.msg);
return 0;
}
查看消息队列
ipcs -q # 查看现有消息队列
ipcrm -q msgid # 根据消息队列标识号,删除消息队列