採用 單一程式碼、參數決定角色 的模式:
-w:發送者 (Writer) — 向隊列寫入訊息-r:接收者 (Reader) — 從隊列讀取訊息#define MSG_KEY 111
#define MAX_TEXT 100
struct msgbuf {
long mtype;
char mtext[MAX_TEXT];
};
int main(int argc, char *argv[]) {
int msqid = msgget(MSG_KEY, 0666 | IPC_CREAT);
struct msgbuf msg;
if (argc < 2) { printf(\"Usage: %s -w|-r\\n\", argv[0]); return 1; }
if (strcmp(argv[1], \"-w\") == 0) {
// 發送者
msg.mtype = 1;
strcpy(msg.mtext, \"hello message queue\");
msgsnd(msqid, &msg, strlen(msg.mtext)+1, 0);
printf(\"write data into message.count:%ld,data:%s\\n\",
strlen(msg.mtext)+1, msg.mtext);
} else if (strcmp(argv[1], \"-r\") == 0) {
// 接收者
msgrcv(msqid, &msg, MAX_TEXT, 0, 0); // 類型 0 = 任意
printf(\"the data of message .count:%ld,data:%s\\n\",
strlen(msg.mtext)+1, msg.mtext);
msgctl(msqid, IPC_RMID, NULL); // 清理
}
return 0;
}
關鍵約束:必須先運行發送者 (-w),再運行接收者 (-r)。
$ ./msg -w
write data into message.count:3,data:hello message queue
$ ./msg -r
the data of message .count:3,data:hello message queue
原因:本範例未實現同步機制,若先啟動接收者,會阻塞在 msgrcv,導致死鎖 (無發送者喚醒)。
// 接收端:非阻塞嘗試
while (1) {
int ret = msgrcv(msqid, &msg, MAX_TEXT, 0, IPC_NOWAIT);
if (ret != -1) {
printf(\"received: %s\\n\", msg.mtext);
break;
}
if (errno == ENOMSG) {
sleep(1); // 等待發送者
continue;
}
perror(\"msgrcv\");
break;
}
// 建立兩個信號量:sem_send (空槽)、sem_recv (滿槽)
// 發送者:P(sem_send) → 寫入 → V(sem_recv)
// 接收者:P(sem_recv) → 讀取 → V(sem_send)
// 實現生產者-消費者模型,彈性控制緩衝區大小
// 定義協議
#define MSG_CMD 1 // 控制命令
#define MSG_DATA 2 // 業務數據
#define MSG_ACK 3 // 確認回覆
// 接收端根據 mtype 分發處理
switch (msg.mtype) {
case MSG_CMD: handle_command(&msg); break;
case MSG_DATA: handle_data(&msg); break;
case MSG_ACK: handle_ack(&msg); break;
}
| 限制常數 | 典型預設值 | 查看/修改方式 |
|---|---|---|
| MSGMNI | 16/32/192 (視系統) | /proc/sys/kernel/msgmni |
| MSGMAX | 8192 bytes | /proc/sys/kernel/msgmax |
| MSGMNB | 16384 bytes | /proc/sys/kernel/msgmnb |
# 臨時調大 (需 root)
echo 65536 > /proc/sys/kernel/msgmax
echo 65536 > /proc/sys/kernel/msgmnb
# 永久生效 (/etc/sysctl.conf)
kernel.msgmax = 65536
kernel.msgmnb = 65536
kernel.msgmni = 1024
ipcs -q:列出所有消息隊列ipcrm -q msqid:手動刪除殘留隊列strace -e trace=msgget,msgsnd,msgrcv,msgctl ./prog:追蹤 IPC 呼叫| 方案 | 優勢 | 劣勢 | 適用場景 |
|---|---|---|---|
| POSIX MQ (mq_*) | 非阻塞通知、優先級、標準化 | 需鏈接 -lrt、部分舊系統不支援 | 新專案、跨平台需求 |
| UNIX Domain Socket | 雙向、傳遞 fd、高效能 | API 較複雜 | 高效能本地通信 |
| System V MQ | 廣泛支援、持久化、類型過濾 | 複製開銷、系統限制、API 老舊 | 維護舊代碼、簡單異步通信 |