- (一)消息队列
- (1)消息队列原理
- (2)Linux系统下的两个宏定义:(其它系统未知)
- (二)消息队列函数
- (1)创建,访问一个消息队列
- (2)添加消息到队列中
- (3)从消息队列中获取消息
- (4)消息队列的控制函数
- (三)简单使用消息队列
(1)消息队列原理
- 消息队列与有名管道相似
- 消息队列不需要管道的打开和关闭管道的操作
- 消息队列并未解决管道满时的阻塞问题
(2)Linux系统下的两个宏定义:(其它系统未知)
- 一个进程向另一个进程发送一个数据块(含有类型)
- 接收进程可以独立地接收不同类型的数据块
- 可以避免有名管道的同步和阻塞问题(未满状态)
- 可以查看紧急消息
- 每个数据块都有一个最大的长度限制(超出限制,消息队列函数失败的原因)
- 所有队列的所有数据块的总长度也有上限
(二)消息队列函数 (1)创建,访问一个消息队列
- 一条消息的最大长度:MSGMAX
- 一个队列的最大长度:MSGMNB
int msgget(key_t key, int msgflg);
- key : 键值,通过同一个键值来访问同一个消息队列(特殊键值IPC_PRIVATE,当前进程可用,私有队列没啥用)
- msgflg : 必须使用IPC_CREAT 和 | 按位或才能创建新的消息队列(没有则创建,已存在则忽略)
- 返回值 :成功返回队列标识符(正整数),失败-1
int msgsnd(int msqid, const void* msg_ptr, size_t msg_sz, int msgflg);
- msqid : msgget的返回的消息队列标识符
- msg_ptr : 是指向准备发送消息(数据块struct my_message{};)的指针
约束条件:
- 消息队列的长度小于系统规定的上限
- 必须以一个长整形long int 变量开始(作为接收函数区分类型的标准)
建议创建一个结构体类型:
struct my_message
{
long int message_type; //消息类型 > 0
...
}
- msg_sz : msg_ptr指向消息的长度(不包含类型的字节大小)
- msgflg : 控制此消息队列达到系统限制(队满),要发生的事。
(IPC_NOWAIT|函数不发送消息并立即返回-1)
队满情况下:如果没有请求类型的消息可用,且未指定IPC_NOWAIT,在MSGFLG中,调用过程被阻塞(等待系统的消息队列中腾出空间),直到下列条件之一:
- 所需类型的消息放置再队列中
- 消息队列被系统删除,系统调用失败,错误号设置为EIDRM
- 调用进程捕获一个信号。在这种情况下,系统调用失败将errno设置为EINTR。
- 返回值:成功返回0,失败-1
int msgrcv(int msaid, void* msg_ptr, size_t msg_sz, long int mstype, int msgflg);
- msqid : 是msgget返回的消息队列的标识符
- msg_ptr : 是一个指向准备接收消息的指针(struct my_message{long int , …};)
- msg_sz : 是接收消息的长度(不包括消息类型字节大小)
- msgtype : 是一个长整数,可以实现简单形式的优先级(优先级消息队列)
注意:
- msgtype为0,获取队列中第一个可用消息
- 大于0,获取同种类型的第一条消息
- 小于0,获取 小于或等于msgtype的绝对值的类型的第一条消息
接受类型使用场景:
- 获取队列中每一个元素,msgtype = 0
- 获取msgtype对应类型的第一条消息
- 获取小于n类型的消息:msgtype = -n;
-
msgflg : 控制队列中没有相应类型的消息可以接收时的事件。设置IPC_NOWAIT,函数立即返回-1;若IPC_NOWAIT标记被清除,进程将会挂起等待相应类型消息到达;
-
返回值:成功返回接收缓存区中的字节大小,消息被复制到msg_ptr指向的缓存空间中,删除消息队列中相应消息,失败返回-1
int msgctl(int msqid, int command, struct msqid_ds* buff);
- msqid : 时msgget返回的消息队列标识符
- command : 3种操作方式如下
| command | 说明 |
|---|---|
| IPC_STAT | 把msqid_ds结构中数据设置为消息队列的当前关联值 |
| IPC_SET | 若进程有足够权限,就把消息队列当前关联值设置成msqid_ds结构中给定的值 |
| IPC_RMID | 删除消息队列 |
- buf : struct msqid_ds类型的指针,结构体如下
(三)简单使用消息队列struct msqid
{
uid_t msg_perm.uid;
uid_t msg_perm.gid;
mode_t msg_perm.mode;
}
a进程写入type = 1 data = "hello world"消息队列中,b进程获取该消息输出
- msg.h
#include#include #include #include struct msgbuf { long int type; //消息类型 char data[32]; //数据 };
- a.c
#include "msg.h"
void SendMessage()
{
//创建消息队列
int msqid = msgget((key_t)8888, IPC_CREAT | 0600);
if(msqid == -1)
{
perror("msgget err");
return;
}
//向消息队列发送消息
struct msgbuf buf;
buf.type = 1;
strcpy(buf.data, "hello world");
if(msgsnd(msqid, &buf, 32, 0) == -1)
{
perror("msgsnd err");
return;
}
}
int main()
{
SendMessage();
return 0;
}
- b.c
#include "msg.h"
void RecvMessage()
{
//创建消息队列
int msqid = msgget((key_t)8888, IPC_CREAT | 0600);
if(msqid == -1)
{
perror("msgget err");
return;
}
//从消息队列获取消息
struct msgbuf buf;
if(msgrcv(msqid, &buf, 32, 1, 0) == -1)
{
perror("msgsnd err");
return;
}
printf("%sn", buf.data);
sleep(2);
//销毁消息队列
if(msgctl(msqid, IPC_RMID, NULL) == -1)
{
perror("msgctl IPC_RMID err");
return;
}
}
int main()
{
RecvMessage();
return 0;
}
结果:



