消息队列
2026/8/25大约 3 分钟
Linux 进程间通信:System V 消息队列
1. 核心原理
消息队列是 Linux 内核维护的一个消息仓库。
发送进程
│
msgsnd()
↓
┌──────────────────┐
│ type=1 hello │
│ type=2 ledon │
│ type=3 quit │
└──────────────────┘
↓
msgrcv()
│
接收进程消息队列以“消息”为单位通信,每条消息都有一个
mtype。
2. 消息结构
struct MyMsgTyp {
long mtype; // 消息类型,必须是第一个成员
char strMsg[256]; // 消息内容
};3. 创建 / 获取消息队列
key_t key = ftok(".", 'a');
int msgid = msgget(key, 0666 | IPC_CREAT);ftok()
ftok(".", 'a');根据:
路径 + 字符生成一个 IPC Key。
msgget()
msgget(key, 0666 | IPC_CREAT);
key → 找到对应消息队列
0666 → 权限
IPC_CREAT → 不存在就创建
msgid → 消息队列标识符4. 发送消息
运行:
./send 2 hellomain():
int main(int argc, char *argv[])得到:
argc = 3
argv[0] → "./send"
argv[1] → "2"
argv[2] → "hello"然后:
msg.mtype = atoi(argv[1]);
strcpy(msg.strMsg, argv[2]);得到:
mtype = 2
strMsg = "hello"最后:
msgsnd(msgid, &msg, strlen(msg.strMsg), 0);把消息放入队列。
5. 接收指定类型的消息
运行:
./recv 2此时:
argc = 2
argv[0] → "./recv"
argv[1] → "2"接收:
msgrcv(msgid, &msg, BUFFER_SIZE, atoi(argv[1]), 0);相当于:
msgrcv(msgid, &msg, BUFFER_SIZE, 2, 0);意思:
只接收
mtype == 2的消息。
例如队列:
type=1 → hello
type=2 → ledon
type=3 → temperature执行:
./recv 2只会取出:
type=2 → ledon其他消息继续留在队列中。
6. mtype 是消息队列的核心
发送:
./send 1 hello
./send 2 ledon
./send 3 temperature队列:
┌──────────────────────┐
│ type=1 → hello │
│ type=2 → ledon │
│ type=3 → temperature │
└──────────────────────┘接收:
./recv 2精准获取:
type=2 → ledon所以:
mtype用于消息分类和选择性接收。
7. 阻塞
msgrcv(..., 0);最后一个参数为 0,表示默认阻塞。
如果当前没有符合类型的消息:
msgrcv()
↓
阻塞等待
↓
其他进程 msgsnd()
↓
消息到达
↓
msgrcv() 返回8. 删除消息队列
msgctl(msgid, IPC_RMID, NULL);删除 System V 消息队列。
9. 与 FIFO 的区别
FIFO:
write()
↓
字节流
↓
read()
消息队列:
msgsnd()
↓
一条完整消息
↓
msgrcv()
↑
mtype 筛选| FIFO | 消息队列 | |
|---|---|---|
| 创建 | mkfifo() | msgget() |
| 发送 | write() | msgsnd() |
| 接收 | read() | msgrcv() |
| 数据 | 字节流 | 消息 |
| 类型 | 无 | mtype |
| 删除 | unlink() | msgctl() |
10. 一句话记忆
ftok() → 生成 Key
msgget() → 获取消息队列
msgsnd() → 发送消息
msgrcv() → 接收指定类型消息
msgctl() → 删除消息队列消息队列 = 内核消息仓库 +
mtype消息分类。
11. 完整源码
发送端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFFER_SIZE 256
struct MyMsgTyp {
long mtype;
char strMsg[BUFFER_SIZE];
};
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("./app <消息类型> <消息内容>\n");
return -1;
}
// 根据路径和字符生成 IPC Key
key_t key = ftok(".", 'a');
// 创建/获取消息队列
int msgid = msgget(key, 0666 | IPC_CREAT);
struct MyMsgTyp msg;
// 设置消息类型
msg.mtype = atoi(argv[1]);
// 设置消息内容
strcpy(msg.strMsg, argv[2]);
// 发送消息
msgsnd(msgid,
&msg,
strlen(msg.strMsg),
0);
printf("消息发送成功: %s, %s\n",
argv[1], argv[2]);
return 0;
}接收端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFFER_SIZE 256
struct MyMsgTyp {
long mtype;
char strMsg[BUFFER_SIZE];
};
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("./app <消息类型>\n");
return -1;
}
// 根据路径和字符生成 IPC Key
key_t key = ftok(".", 'a');
// 创建/获取消息队列
int msgid = msgget(key, 0666 | IPC_CREAT);
struct MyMsgTyp msg;
memset(&msg, 0, sizeof(msg));
// 接收指定类型的消息
msgrcv(msgid,
&msg,
BUFFER_SIZE,
atoi(argv[1]),
0);
printf("读取成功! 消息类型: %ld, 消息内容: %s\n",
msg.mtype,
msg.strMsg);
return 0;
}使用
# 发送
./send 1 hello
./send 2 ledon
./send 3 temperature
# 接收 2 号消息
./recv 2结果:
读取成功! 消息类型: 2, 消息内容: ledon核心就这一条:发送时指定 mtype,接收时指定 mtype,从而实现消息的分类与精准接收。

