进程通信之消息队列
消息队列
消息队列是一种进程间通信(IPC)机制,允许进程以消息的形式传递数据。它通过在内核中维护的队列实现,提供了异步通信的能力。消息队列由键值唯一标识,支持一个或多个进程之间的数据传输。
相关函数
msgget
- 功能:创建或获取一个消息队列
- 函数原型:
int msgget(key_t key, int msgflg);
- 参数:
key
:消息队列的键即标识,可以通过ftok
生成msgflg
:访问权限。IPC_CREAT
—— 如果 key 不存在,则创建IPC_EXCL
—— 如果 key 存在,则返回失败
- 返回值:成功返回消息队列标识符(非负整数),失败返回
-1
msgsnd
- 功能:向消息队列发送消息
- 原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 参数:
msqid
:消息队列标识符,也就是上述创建的返回值msgp
:指向消息的指针,是个结构体,但需要自己手动定义(放下面了)msgsz
:消息正文的大小(不包括消息类型)msgflg
:操作标志(如IPC_NOWAIT
非阻塞发送,即如果包含此选项,则消息队列满时,不发送该消息,立即返回 -1。反之,如果不包含此选项,则消息队列满时,挂起本进程,直到消息队列由空间可用。)
// 结构体的定义
struct message {
long msg_type; // 消息类型,必须为 long 类型即 long int
char msg_text[100]; // 消息正文,数组大小自定义
};
- 返回值:成功返回
0
,失败返回-1
msgrcv
- 功能:从消息队列接收消息
- 函数原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
- 参数:
msqid
:消息队列标识符,即创建消息队列时候的函数返回值msgp
:存储接收到的消息的指针(上面msgsnd
已介绍)msgsz
:期望接收的消息正文大小msgtyp
:消息类型(0
表示接收任意类型)0
:忽略消息类型,从消息队列中接收队列中的第一条消息(按照队列的 FIFO 顺序)- 大于
0
:从消息队列中接收类型为msg_type
的第一条消息,如果队列中没有匹配的消息,进程会阻塞,直到符合条件的消息到达(或设置了非阻塞标志) - 小于
0
:从消息队列中接收类型值小于等于|msg_type|
(绝对值)的消息,选择类型值小于等于|msg_type|
且优先级最高的消息(类型值越小,优先级越高)
msgflg
:操作标志(如IPC_NOWAIT
非阻塞接收,上述msgsnd
已经介绍)
- 返回值:成功返回消息队列标识符(非负整数),失败返回
-1
msgctl
- 功能:控制和管理消息队列
- 原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);`
- 参数:
msqid
:消息队列标识符,即创建消息队列时候的函数返回值cmd
:控制命令,指定要对消息队列执行的操作IPC_STAT
:获取消息队列的当前状态IPC_SET
:设置消息队列的属性IPC_RMID
:从系统中删除消息队列
buf
:指向一个msqid_ds
结构的指针,用于传递或接收消息队列的信息IPC_STAT
:由内核填充buf
,包含消息队列的当前状态,然后作为传出参数,用户可以进行读取数据查看消息队列状态IPC_SET
:用户手动填充buf
中的部分字段,将其作为传入参数,修改消息队列的属性IPC_RMID
:此参数可以为NULL
,因为该操作不需要buf
- 返回值:成功返回
0
,失败返回-1
示例
发送方
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// 定义消息结构
struct msgbuf {
long msg_type; // 消息类型
char msg_text[256]; // 消息内容
};
int main()
{
key_t key;
int msqid;
struct msgbuf msg;
// 生成唯一键值
key = ftok(".", 123);
if (key == -1) {
perror("ftok");
exit(EXIT_FAILURE);
}
// 创建或获取消息队列
msqid = msgget(key, IPC_CREAT | 0666);
if (msqid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
printf("Message queue created with ID: %d\n", msqid);
// 循环发送消息
for (int i = 1; i <= 5; ++i)
{
msg.msg_type = 1; // 消息类型为 1
snprintf(msg.msg_text, sizeof(msg.msg_text), "Message %d from sender", i);
if (msgsnd(msqid, &msg, strlen(msg.msg_text) + 1, 0) == -1) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
printf("Sent: %s\n", msg.msg_text);
sleep(1); // 模拟延时
}
return 0;
}
接收方
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// 定义消息结构
struct msgbuf {
long msg_type; // 消息类型
char msg_text[256]; // 消息内容
};
int main()
{
key_t key;
int msqid;
struct msgbuf msg;
// 生成唯一键值
key = ftok(".", 123);
if (key == -1) {
perror("ftok");
exit(EXIT_FAILURE);
}
// 获取消息队列
msqid = msgget(key, 0666);
if (msqid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
printf("Message queue opened with ID: %d\n", msqid);
// 循环接收消息
while (1)
{
if (msgrcv(msqid, &msg, sizeof(msg.msg_text), 1, 0) == -1) {
perror("msgrcv");
exit(EXIT_FAILURE);
}
printf("Received: %s\n", msg.msg_text);
// 接收到特定内容时退出
if (strcmp(msg.msg_text, "exit") == 0) {
printf("Received exit signal. Exiting...\n");
break;
}
}
return 0;
}
输出
// 发送方
Message queue created with ID: 12345
Sent: Message 1 from sender
Sent: Message 2 from sender
Sent: Message 3 from sender
Sent: Message 4 from sender
Sent: Message 5 from sender
// 接收方
Message queue opened with ID: 12345
Received: Message 1 from sender
Received: Message 2 from sender
Received: Message 3 from sender
Received: Message 4 from sender
Received: Message 5 from sender
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探