首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

System V 消息隊列 IPC 詳解:msgget、msgsnd、msgrcv、msgctl 完整指南

     編輯:關於C語言

消息隊列核心概念

消息隊列是 System V IPC 機制的一種,提供 內核持久化的訊息緩衝區。特點:

  • ✅ 訊息為單位 (而非位元組流),保持邊界
  • ✅ 支援訊息類型/優先級,接收端可選擇性讀取
  • ✅ 發送/接收進程可異步運行,訊息在隊列中暫存
  • ✅ 突破進程親緣關係限制,任意進程可通過 key 訪問

四大核心函數詳解

msgget - 建立/獲取隊列

int msgget(key_t key, int msgflg);
參數說明
keyIPC 鍵值 (ftok 產生或 IPC_PRIVATE)
msgflg權限 | IPC_CREAT | IPC_EXCL 等標誌

返回:隊列標識符 (msqid),失敗返 -1

msgsnd - 發送訊息

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

訊息結構要求:第一成員 必須是 long 類型 (mtype),用於類型過濾

struct my_msg {
    long mtype;       // 訊息類型 (>0)
    char mtext[256];  // 訊息內容
    // 可擴展其他欄位
};
參數說明
msqidmsgget 返回的隊列 ID
msgp指向訊息結構體的指標
msgsz訊息資料部分大小 (不含 mtype)
msgflgIPC_NOWAIT (非阻塞) 或 0 (阻塞等待)

msgrcv - 接收訊息

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgtyp 值接收行為
0接收隊列中第一條訊息 (FIFO)
>0接收第一條 mtype == msgtyp 的訊息
<0接收第一條 mtype ≤ |msgtyp| 的訊息 (優先級模式)

返回:實際讀取的資料部分位元組數,失敗返 -1

msgctl - 隊列控制

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
命令功能buf 用途
IPC_RMID刪除隊列忽略 (可傳 NULL)
IPC_STAT獲取隊列狀態填充 msqid_ds 結構
IPC_SET設置隊列屬性從 msqid_ds 讀取屬性

msqid_ds 關鍵成員 (內核定義):

struct msqid_ds {
    struct ipc_perm msg_perm;  // 權限/擁有者
    time_t msg_stime;          // 最後 msgsnd 時間
    time_t msg_rtime;          // 最後 msgrcv 時間
    time_t msg_ctime;          // 最後變更時間
    unsigned long msg_cbytes;  // 當前隊列位元組數
    unsigned long msg_qnum;    // 當前訊息數
    unsigned long msg_qbytes;  // 隊列最大位元組數
    pid_t msg_lspid;           // 最後發送者 PID
    pid_t msg_lrpid;           // 最後接收者 PID
};

完整使用流程

發送端 (參數 -w)

// 1. 定義訊息類型
struct msgbuf {
    long mtype;
    char data[100];
} msg;

 // 2. 獲取/建立隊列
int msqid = msgget(111, 0666 | IPC_CREAT);

// 3. 準備數據
msg.mtype = 1;  // 類型 1
strcpy(msg.data, \"hello message queue\");

// 4. 發送 (阻塞模式)
msgsnd(msqid, &msg, strlen(msg.data)+1, 0);
printf(\"write data: %s\\n\", msg.data);

接收端 (參數 -r)

// 1. 獲取現有隊列
int msqid = msgget(111, 0666);

// 2. 接收 (類型 0 表示任意)
struct msgbuf msg;
msgrcv(msqid, &msg, sizeof(msg.data), 0, 0);
printf(\"read data: %s\\n\", msg.data);

// 3. 可選:刪除隊列 (通常由最後一個進程清理)
msgctl(msqid, IPC_RMID, NULL);

執行驗證

$ ./msg -w
write data into message.count:3,data:hello message queue

$ ./msg -r
the data of message .count:3,data:hello message queue

關鍵注意事項

  1. 訊息結構體對齊:mtype 必須是第一個成員,且為 long 類型
  2. msgsz 計算:sizeof(struct) - sizeof(long),不含 mtype
  3. 阻塞 vs 非阻塞:IPC_NOWAIT 避免死鎖,但需處理 EAGAIN
  4. 隊列限制:系統限制 MSGMNI (隊列數)、MSGMAX (單訊息大小)、MSGMNB (隊列總大小)
  5. 權限管理:類似檔案權限,需注意進程有效 UID/GID
  6. 清理責任:約定由最後一個使用者調用 IPC_RMID

進階用法:多類型訊息優先級處理

// 定義多種訊息類型
#define MSG_TYPE_URGENT   10  // 高優先級
#define MSG_TYPE_NORMAL   5   // 普通
#define MSG_TYPE_LOW      1   // 低優先級

// 接收端:優先處理緊急訊息
while (1) {
    // 先嘗試接收緊急訊息 (非阻塞)
    if (msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_URGENT, IPC_NOWAIT) != -1) {
        handle_urgent(&msg);
        continue;
    }
    // 再接收普通訊息
    if (msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_NORMAL, IPC_NOWAIT) != -1) {
        handle_normal(&msg);
        continue;
    }
    // 最後阻塞等待低優先級
    msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_LOW, 0);
    handle_low(&msg);
}

與其他 IPC 比較

特性消息隊列管道/FIFO共享記憶體
資料單位訊息 (有邊界)位元組流 (無邊界)任意結構
同步機制內建阻塞/非阻塞內建阻塞需外部同步 (信號量)
優先級支援不支援不支援
持久性內核持久化進程結束即銷毀進程結束即銷毀
效能中等 (需複製)中等最高 (零複製)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved