消息對列的優勢:緩存
1.消息隊列是一種先進先出的隊列型數據結構,保證先送的貨物先到達。服務器
2.消息隊列將輸出的信息進行了打包處理,這樣能夠保證以每一個消息爲單位進行接收數據結構
3.消息隊列還能夠對貨物進行分類,標記各類類別的貨物。函數
消息隊列的最佳定義是:內核地址空間中的內部鏈表。消息能夠順序地發送到隊列中,並以幾種不一樣的方式從隊列中獲取。固然,每一個消息隊列都是由 IPC標識符所惟一標識的。spa
一些命令:查看IPC對象 ipcs (-q,-s ,-m)指針
查詢IPC對象的所有屬性: ipcs 至關於 ipcs -qsm對象
查詢IPC對象的所有屬性: ipcs -a隊列
刪除IPC對象 ipcrm (-q,-s, -a ,-m) -id進程
每一個IPC對象都有惟一的IPC對象的標識符。不一樣類型IPC能夠相同。經過標識符在系統內核惟一肯定IPC對象。ip
建立IPC對象,必須制定一個IPC關鍵字,關鍵字爲32位整數 , KEY描述。
一.管道則只能傳送無格式字節流,
消息隊列(也叫報文隊列)客服了這些缺點:
消息隊列就是一個消息的鏈表。
能夠把消息看做一個記錄,具備特定的格式。
二. 在某個進程往一個隊列寫入消息以前,並不須要另外某個進程在該隊列上等待消息的到達。這跟管道和FIFO是相反的,對後二者來講,除非讀出者已存在,不然先有寫入者是沒有意義的。
管道和FIFO都是隨進程持續的,XSI IPC(消息隊列、信號量、共享內存)都是隨內核持續的。
當一個管道或FIFO的最後一次關閉發生時,仍在該管道或FIFO上的數據將被丟棄。消息隊列,除非內核自舉或顯式刪除,不然其一直存在。
消息隊列跟命名管道有很多的相同之處,經過與命名管道同樣,消息隊列進行通訊的進程能夠是不相關的進程,同時它們都是經過發送和接收的方式來傳遞數據的。在命名管道中,發送數據用write,接收數據用read,則在消息隊列中,發送數據用msgsnd,接收數據用msgrcv。並且它們對每一個數據都有一個最大長度的限制。
與命名管道相比,消息隊列的優點在於
1、消息隊列也能夠獨立於發送和接收進程而存在,從而消除了在同步命名管道的打開和關閉時可能產生的困難。
2、同時經過發送消息還能夠避免命名管道的同步和阻塞問題,不須要由進程本身來提供同步方法。
3、接收程序能夠經過消息類型有選擇地接收數據,而不是像命名管道中那樣,只能默認地接收。
4. 消息隊列提供了消息數據的自動拆分,同時不能接受兩次發送的消息。
對於系統中的每一個消息隊列,內核維護一個定義在<sys/msg.h>頭文件中的信息結構。
struct msqid_ds {
struct ipc_perm msg_perm ;
struct msg* msg_first ; //指向隊列中的第一個消息
struct msg* msg_last ; //指向隊列中的最後一個消息
……
} ;
建立消息對列:
1.建立一個key,使用函數ftok()
msgget函數
函數msgget,其功能是打開一個現存隊列或建立一個新隊列。
#include <sys/msg.h>
int msgget (key_t key, int oflag) ;
返回值是一個整數標識符,其餘三個msg函數就用它來指代該隊列。它是基於指定的key產生的,而key既能夠是ftok的返回值,也能夠是常值IPC_PRIVATE。
若是key爲IPC_PRIVATE,則函數建立關鍵字爲0的消息隊列。雖然要求關鍵字惟一,但可建立多個關鍵字爲0的消息隊列。
oflag:低9位是訪問權限的組合,其餘位指定消息隊列的建立方式。能夠是IPC_CREATE(有則打開,沒有則建立)或IPC_CREATE | IPC_EXCL(建立時若是已存在則報錯)
msgsnd函數
使用msgsnd打開一個消息隊列後,咱們使用msgsnd往其上放置一個消息。
#include <sys/msg.h>
int msgsnd (int msqid, const void *ptr, size_t length, int flag) ;
1. msqid是由msgget返回的標識符。
2. ptr是一個結構指針,該結構具備以下模板(咱們須要按這個模板本身定義結構體,只要結構的第一個成員維持long型不變)
struct mymesg {
long mtype ; //消息類型(大於0)
char mtext[512] ; //消息數據
} ;//結構體的名字和其中變量名都由咱們本身肯定,咱們只要按照這個模板定義便可。
消息數據mtext中,任何形式的數據都是容許的,不管是二進制數據仍是文本,內核根本不解釋消息數據的內容。(咱們能夠在消息的數據部分 再分割一部分 根據須要定義本身的通訊協議)
3. 參數length指定待發送消息數據部分的長度。注意是消息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型消息類型成員變量的長度。必須大於0
4. 參數flag的值能夠指定爲IPC_NOWAIT。這相似於文件IO的非阻塞IO標誌。若消息隊列已滿,則指定IPC_NOWAIT使得msgsnd當即出錯返回EAGAIN。
若是沒有指定IPC_NOWAIT,則進程阻塞直到下述狀況出現爲止:①有空間能夠容納要發送的消息 ②從系統中刪除了此隊列(返回EIDRM「標識符被刪除」)③捕捉到一個信號,並從信號處理程序返回(返回EINTR)
用於控制當前消息隊列滿或隊列消息到達系統範圍的限制時將要發生的事情。???
◇調用成功,消息數據的一分份副本將被放到消息隊列中,並返回0,失敗時返回-1.
阻塞的兩種狀況:
消息隊列滿,要發送的數據 + 消息隊列已使用的字節數,超過消息隊列可容納的最大字節數。
消息總數滿:系統中全部消息對列記載的消息總數已經超過系統的上限值。
error的值:消息對列被刪除,error置爲EIDRM
發送消息過程當中接到信號,消息發送中斷,,error置爲EINTR
設置爲非阻塞,當消息隊列滿時,error置爲EAGAIN
msgrcv函數
使用msgrcv函數從某個消息隊列中讀出一個消息。
#include <sys/msg.h>
ssize_t msgrcv (int msqid, void* ptr, size_t length, long type, int flag) ;
參數ptr指定所接收消息的存放位置。參數length指定了數據部分大小(只想要多長的數據)
參數length,包括消息類型的部分。
參數type指定但願從隊列中讀出什麼樣的消息。
type == 0 返回隊列中的第一個消息
type > 0 返回隊列中消息類型爲type的第一個消息
type < 0 返回隊列中消息類型值小於或等於type絕對值的消息,若是這種消息有若干個。則取類型值最小的消息。
(若是一個消息隊列由多個客戶進程和一個服務器進程使用,那麼type字段能夠用來包含客戶進程的進程ID)
參數flag能夠指定爲IPC_NOWAIT,使操做不阻塞。
MSG_NOERROR , 截斷讀取消息,當接收到的消息長度大於緩衝區長度時,截斷消息。只接收length長,剩餘的下次接收。
沒有設置MSG_NOERROR ,發生上述狀況則error置爲E2BIG
◇調用成功時,該函數返回放到接收緩存區中的字節數,消息被複制到由msg_ptr指向的用戶分配的緩存區中,而後刪除消息隊列中的對應消息。失敗時返回-1。
msgctl函數
msgctl函數提供在一個消息隊列上的各類控制操做。
查詢消息隊列數據結構,改變消息隊列訪問權限,改變消息隊列屬主信息和刪除消息隊列
#include <sys/msg.h>
int msgctl (int msqid, in cmd, struct msqid_ds * buff) ;
參數cmd說明對由msqid指定的隊列要執行的命令:
IPC_STAT :取此隊列的msqid_ds結構,並將它存放在buf指向的結構中。
IPC_SET :按由buf指向結構中的值,設置與此隊列相關結構中的字段。
IPC_RMID:從系統中刪除該消息隊列以及仍在該隊列中的全部數據。
(這三條命令也可用於信號量和共享存儲)
常見應用模型:
1.單一消息對列完成對等進程間的雙向通訊模型
2.雙消息隊列完成對等進程間的雙向通訊
3.單一消息隊列完成客戶-服務器件的雙向通訊
4.雙消息隊列完成客戶-服務器進程間的雙向通訊