Linux處理序間通訊(System V) --- 訊息佇列
訊息佇列 IPC 原理
訊息佇列是訊息的鏈式隊列,如為訊息佇列的模型。整個訊息佇列有兩種類型的資料結構。
1.msqid_ds 訊息佇列資料結構:描述整個訊息佇列的屬性,主要包括整個訊息佇列的許可權、擁有者、兩個重要的指標(分別指向訊息佇列的第一個訊息和最後一個訊息)。2.msg 訊息佇列資料結構:整個訊息佇列的主體,一個訊息佇列有若干個訊息,每個訊息資料結構的基本成員包括訊息類型、訊息大小、訊息內容指標和下一個訊息資料結構的位置。
訊息佇列還可以基於類型處理,但是,訊息佇列的 FIFO 原則僅僅適用於同類型的訊息。在 Linux 中,對訊息佇列進行了以下規定(不同 Linux 版本的話值可能會不同):
1.預設情況下,整個系統最多允許有16個訊息佇列。2.每個訊息佇列最大為16384位元組。3.訊息佇列中的每個訊息最大為8192位元組。
這些內容在 /usr/include/linux/msg.h 中進行定義:
#define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */
訊息佇列的基本屬性
出於 /usr/include/linux/msg.h 檔案
訊息佇列管理
1.建立訊息佇列:
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>/* 第一個參數為key值,一般由ftok()函數獲得;第二個參數為存取權限 */int msgget(key_t key, int msgflg);
2.訊息佇列屬性控制
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>/* * 第一個參數為訊息佇列ID,由msgget獲得 * 第二個參數為控制指令 * 第三個參數為資料傳遞的載體 */int msgctl(int msqid, int cmd, struct msqid_ds *buf);
控制指令如下:
3.發送訊息佇列
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>/* * 第一個參數為訊息佇列ID * 第二個參數 msgp 指向定義的緩衝區 * 第三個參數為發送訊息的大小 * 第四個參數一般高為0,阻塞調用進程 */int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
4.從訊息佇列接收訊息
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>/* * 第一個參數為訊息佇列ID * 第二個參數為臨時訊息資料結構,用於儲存訊息 * 第三個參數為接收訊息的大小 * 第四個參數用於指定請求的訊息類型 * 第五個參數一般設定為0,阻塞調用進程 */ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
其中訊息資料結構應定義如下:
/* From /usr/include/linux/msg.h */struct msgbuf { long mtype; /* 訊息類型 */ char mtext[1]; /* 儲存訊息位置,需要重新定義 */};
訊息佇列應用執行個體
建立兩個進程,使用訊息佇列進行通訊,一個進程發送訊息,另一個進程接收訊息。
發送端:
#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdlib.h>#include <string.h>struct msgbuf { long mtype; char mtext[50]; };int main(){ int key, msg_id; static struct msgbuf buf; key = ftok(".", 1); msg_id = msgget(key, IPC_CREAT | 0600); /* 設定訊息的類型 */ buf.mtype = 1; while(1){ fgets(buf.mtext, 50, stdin); /* 輸入quit退出進程,並刪除隊列 */ if(!strncmp(buf.mtext, "quit", 4)){ msgctl(msg_id, IPC_RMID, 0); exit(0); } /* 將訊息發送到隊列 */ msgsnd(msg_id, (void *)&buf, sizeof(buf), 0); } return 0;}
接收端:
#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>struct msgbuf { long mtype; char mtext[50]; };int main(){ int key, msg_id; static struct msgbuf buf; key = ftok(".", 1); msg_id = msgget(key, IPC_CREAT | 0600); /* 設定訊息類型 */ buf.mtype = 1; while(1){ /* 從訊息佇列接收訊息 */ msgrcv(msg_id, (void*)&buf, sizeof(buf), buf.mtype, 0); printf("Recv msg : %s \n", buf.mtext); } return 0;}
運行結果: