在Linux环境下,使用C/C++实现进程间通信(IPC)的消息队列(Message Queue)可以通过 **System V消息队列** 或 **POSIX消息队列** 两种方式实现。下面分别给出两种方法的完整代码示例。
---
## **1. System V 消息队列**
System V消息队列是传统的Unix IPC机制,通过 `msgget`、`msgsnd`、`msgrcv` 等系统调用实现。
### **发送端(sender.c)**
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// 定义消息结构体
struct msg_buffer {
long msg_type; // 消息类型(必须 > 0)
char msg_text[100]; // 消息内容
};
int main() {
key_t key;
int msg_id;
struct msg_buffer message;
// 生成唯一的key(可以用ftok或直接指定)
key = ftok("msg_queue", 65); // 使用文件路径和项目ID生成key
if (key == -1) {
perror("ftok");
exit(1);
}
// 创建消息队列(如果不存在则创建,权限 0666)
msg_id = msgget(key, 0666 | IPC_CREAT);
if (msg_id == -1) {
perror("msgget");
exit(1);
}
// 设置消息类型(必须 > 0)
message.msg_type = 1;
// 写入消息内容
printf("Enter message to send: ");
fgets(message.msg_text, sizeof(message.msg_text), stdin);
// 发送消息(最后一个参数 0 表示阻塞模式)
if (msgsnd(msg_id, &message, sizeof(message.msg_text), 0) == -1) {
perror("msgsnd");
exit(1);
}
printf("Message sent: %s\n", message.msg_text);
return 0;
}
```
### **接收端(receiver.c)**
```c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// 定义消息结构体(必须和发送端一致)
struct msg_buffer {
long msg_type;
char msg_text[100];
};
int main() {
key_t key;
int msg_id;
struct msg_buffer message;
// 生成相同的key
key = ftok("msg_queue", 65);
if (key == -1) {
perror("ftok");
exit(1);
}
// 获取消息队列
msg_id = msgget(key, 0666 | IPC_CREAT);
if (msg_id == -1) {
perror("msgget");
exit(1);
}
// 接收消息(最后一个参数 0 表示接收第一个可用的消息)
if (msgrcv(msg_id, &message, sizeof(message.msg_text), 1, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("Received message: %s\n", message.msg_text);
// 删除消息队列(可选)
if (msgctl(msg_id, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
return 0;
}
```
### **编译运行**
```bash
gcc sender.c -o sender
gcc receiver.c -o receiver
./sender # 发送消息
./receiver # 接收消息
```
---
## **2. POSIX 消息队列**
POSIX消息队列更现代化,使用 `mq_open`、`mq_send`、`mq_receive` 等函数。
### **发送端(sender_posix.c)**
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#define QUEUE_NAME "/my_msg_queue"
#define MAX_MSG_SIZE 100
int main() {
mqd_t mq;
char buffer[MAX_MSG_SIZE];
// 打开或创建消息队列(O_CREAT 表示不存在则创建)
mq = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0666, NULL);
if (mq == (mqd_t)-1) {
perror("mq_open");
exit(1);
}
printf("Enter message to send: ");
fgets(buffer, MAX_MSG_SIZE, stdin);
// 发送消息(优先级设为 0)
if (mq_send(mq, buffer, strlen(buffer), 0) == -1) {
perror("mq_send");
exit(1);
}
printf("Message sent: %s\n", buffer);
mq_close(mq);
return 0;
}
```
### **接收端(receiver_posix.c)**
```c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#define QUEUE_NAME "/my_msg_queue"
#define MAX_MSG_SIZE 100
int main() {
mqd_t mq;
char buffer[MAX_MSG_SIZE + 1];
unsigned int prio;
// 打开消息队列(只读)
mq = mq_open(QUEUE_NAME, O_RDONLY);
if (mq == (mqd_t)-1) {
perror("mq_open");
exit(1);
}
// 接收消息
if (mq_receive(mq, buffer, MAX_MSG_SIZE, &prio) == -1) {
perror("mq_receive");
exit(1);
}
printf("Received message: %s\n", buffer);
mq_close(mq);
mq_unlink(QUEUE_NAME); // 删除队列
return 0;
}
```
### **编译运行**
```bash
gcc sender_posix.c -o sender_posix -lrt
gcc receiver_posix.c -o receiver_posix -lrt
./sender_posix # 发送消息
./receiver_posix # 接收消息
```
---
## **对比**
| 特性 | System V 消息队列 | POSIX 消息队列 |
|-------------|----------------|---------------|
| **API** | `msgget`, `msgsnd`, `msgrcv` | `mq_open`, `mq_send`, `mq_receive` |
| **权限控制** | 基于 `IPC_CREAT` | 基于文件权限 |
| **队列名称** | 通过 `key_t`(如 `ftok`) | 直接使用路径名(如 `/my_queue`) |
| **编译选项** | 无需额外库 | 需 `-lrt` 链接库 |
| **跨平台** | 传统Unix支持 | 较新系统支持 |
---
## **总结**
- **System V消息队列** 适用于传统Unix/Linux环境。
- **POSIX消息队列** 更现代,支持优先级,推荐新项目使用。
- 如果只是简单通信,两者均可,但POSIX更清晰。
你可以根据项目需求选择合适的实现方式!
浙公网安备 33010602011771号