(三)程序間通訊方式-----訊息佇列
訊息佇列
訊息佇列,是訊息的連結表,存放在核心中。一個訊息佇列由一個識別符號(即佇列ID)來標識。使用者程序可以向訊息佇列新增訊息,也可以向訊息佇列讀取訊息。
同管道檔案相比,訊息佇列中的每個訊息指定特定的訊息型別,接收的時候可以不需要按照佇列次序讀取,可以根據自定義型別接收特定型別的訊息。我們可以將訊息看成一個具有特定格式以及特定的優先順序的一個記錄,對訊息佇列有寫許可權的程序可以向訊息佇列中按照一定規則新增訊息,對於訊息佇列有讀許可權的程序可以從訊息佇列中讀取訊息。
訊息佇列特點
- 訊息佇列是面向記錄的,其中的訊息具有特定的格式和特定的優先順序
- 訊息佇列獨立於傳送與接收程序,即便程序終止時,訊息佇列及其內容都不會被改變
- 訊息佇列可以實現隨機查詢,不一定非得按照佇列的先進先出獲取訊息,可以按照訊息型別獲取
訊息佇列的操作
1:訊息佇列的建立或獲取
#include<sys/msg.h>
int msgget(key_t key,int flag); //開啟一個現存訊息佇列或者建立一個新佇列
//成功返回訊息佇列ID,失敗返回-1
與其他IPC一樣,程式必須提供一個以鍵來命名的訊息佇列 。flag是一個許可權標誌,與檔案的訪問許可權一樣,IPC_CREAT可與flag做或操作,表示當key所命名的訊息佇列不存在時建立一個訊息佇列,如果key所命名的訊息佇列存在時,IPC_CREAT標誌會被忽略,而只返回一個識別符號。
IPC_CREAT 如果不存在,則建立一個,否則直接開啟已存在的
IPC_EXCL 只有在不存在的時候,新的才建立,否則就產生錯誤
與semget相似,我們在用獲取函式判斷是否訊息佇列存在時,有兩種寫法
int id=msgget(key,IPC_CREAT|0664); //如果存在直接返回id值 int id=msgget(key,IPC_CREAT|0664); //判斷是否存在,不存在返回-1 id=msgget(key,IPC_CREAT|0664); //本次呼叫會返回id值 int id=msgget(key,IPC_CREAT&IPC_EXCL) //如果存在直接返回id值 int id=msgget(key,IPC_CREAT&IPC_EXCL) //判斷是否存在,不存在返回-1 id=msgget(key,IPC_CREAT&IPC_EXCL) //本次呼叫會返回id值
2:把訊息新增到訊息佇列中
#include<sys/msg.h>
int msgsnd(int msqid,const void *ptr, size_t size, int flag);
//成功返回0,出錯返回-1
msqid是由msgget函式返回的訊息佇列識別符號(id值)。ptr是一個指向準備傳送訊息的指標,但是訊息的資料結構卻有一定的要求,指標ptr所指向的訊息結構一定要是以一個長整型成員變數開始的結構體,它包含了正的整型訊息型別,在其後緊跟著訊息資料。(若nbytes是0,則無訊息資料。)若傳送的最長訊息是512位元組,則可定義下列結構:接收函式將用這個成員來確定訊息的型別。所以訊息結構要定義成這樣:
struct mymesq
{
long mtype; /*正的整數訊息型別
char mtest[512]; /*訊息資料,最長為512位元組
}
nbytes是ptr指向的訊息的長度,注意是訊息的長度,而不是整個結構體的長度,也就是說nbytes是不包括長整型訊息型別成員變數的長度。
flag用於控制當前訊息佇列滿或佇列訊息到達系統範圍的限制時將要發生的事情。引數flag的值可以置為為IPC_NOWAIT。若訊息佇列已滿(或者是佇列中的訊息總數等於系統限制值,或佇列中的位元組總數等於系統系統限制值),則指定IPC_NOWAIT使得msgsnd立即出錯返回EAGAIN。如果沒有指定IPC_NOWAIT,則程序阻塞直到下述情況出現為止:有空間可以容納要傳送的訊息,從系統中刪除此佇列;或捕捉到一個訊號,並從訊號處理程式返回。在第二種情況下,返回EIDRM(識別符號被刪除)。最後一種情況則返回EINTR。
如果呼叫成功,訊息資料的一分副本將被放到訊息佇列中,並返回0,失敗時返回-1.