程序間通訊方式(IPC)
程序間通訊(Inter process communication,簡稱IPC)指的是程序之間的資訊交換,程序間通訊的方式有很多,比如管道通訊、訊號通訊、共享記憶體、訊息佇列、訊號量組、POSIX訊號量等。
程序間通訊可以達到資料傳輸、共享資源、控制程序等目的,方便使用者對程序進行控制和管理。
當然,Linux系統中這麼多種程序間的通訊方式並不是一同出現的,而是在不同時期被設計出來,Linux系統屬於類Unix系統,所以Linux系統繼承了很多Unix系統的設計,比如Unix系統的System-V版本中就引入了三種程序間通訊方式,分別是訊息佇列、共享記憶體、訊號量組。這三種通訊方式也被稱為System-V IPC物件。
訊息佇列的概念
-
Linux系統中訊息佇列(Message Queue)是程序間通訊的一種方式,這種通訊機制的好處是可以傳輸指定型別(使用者可以自行定義)的資料,相同型別的資料根據到達順序在佇列中進行排隊。
-
不同型別的資料不能處於同一個佇列中,也就是說系統中可能存在多個訊息佇列,每個訊息佇列中的資料型別都是不同的,所以使用者打算讀取訊息佇列中的資料時也需要指定資料型別,才可以從儲存該型別資料的訊息佇列中讀取有效資料。
如何指定某個訊息佇列進行訊息傳輸?
Linux系統下每個被建立的訊息佇列都具有獨屬於自己的一個Key值,程序可以透過指定訊息佇列的Key值來選擇訊息佇列進行資料傳輸。
可透過shell命令:ipcs -a來檢視系統下所有IPC物件的資訊
訊息佇列的建立
使用者可透過Linux系統提供的msgget()函式介面開啟或者建立一個訊息佇列。
-
第一個引數需要傳入一個key_t的值,也就是對應的要建立的訊息佇列的key值(使用者可透過ftok函式自行指定key值)
-
第二個引數需要指定訊息佇列的標誌/許可權,IPC_CREAT為訊息佇列不存在則建立,IPC_EXCL為訊息佇列存在則函式呼叫失敗,用9位元組進行許可權設定(參考open函式的made型別)
-
成功返回訊息佇列的識別符號,失敗則返回-1並設定錯誤碼
shell命令ipcmk也可用於建立IPC物件
訊息佇列的資料收發
Linux系統中提供了msgsnd()的函式介面,使用者利用該函式可以向指定的訊息佇列傳送資訊。
msgrcv()用於資料讀取,使用者利用該函式可以向指定的訊息佇列讀取資訊
資料傳送——msgsnd()
-
第一個引數msgid指訊息佇列的識別符號,透過msgget函式返回
-
第二個引數msgp指向struct msgbuf型別的結構體指標,mtype指訊息型別,mtext指訊息正文
-
第三個引數msgsz指訊息正文的大小。該值必須為非負整數
-
第四個引數msgflg指訊息佇列的標誌。IPC_NOWAIT不阻塞,此時當待寫入資訊大於訊息佇列長度時,函式直接返回並報錯。預設阻塞情況下,會阻塞到訊息佇列的容量足夠容納待寫入資料時解除阻塞。
資料接收——msgrcv()
-
第一個引數msgid指訊息佇列的識別符號,透過msgget函式返回
-
第二個引數msgp指存放訊息的快取地址,該地址下儲存的是struct msgbuf型別結構體
-
第三個引數msgsz指的是存放訊息的快取的大小,按照位元組計算,如果訊息正文的大小大於使用者設定的快取大小,則根據msgflg是否為MSG_NOERROR進行判斷,如果msgflg設定為MSG_NOERROR ,則可以讀取對應位元組的訊息,如果msgflg沒有設定,則無法讀取訊息並報錯。
-
第四個引數:msgtyp指的是要接收訊息的型別,在呼叫msgsnd函式時構造的訊息結構體中有該成員的值。
- 等於0:不區分型別返回MSG中的第一個訊息
- 大於0:讀取型別為指定msgtyp的第一個訊息(若msgflg被配置了MSG_EXCEPT則讀取除了型別為msgtyp以外的第一個訊息)
- 小於0:讀取型別小於等於msgtyp絕對值的第一個具有最小型別的訊息。(例如當MSG物件中有型別為3、1、5型別訊息若干條,當msgtyp為-3時,型別為3的第一個訊息將被讀取。)
-
第五個引數:msgflg指的是接收訊息選項,如果msgflg設定為0,指的是預設接收模式,在MSG中無指定型別訊息時阻塞。
- IPC_NOWAIT:非阻塞接收模式,當MSG中沒有指定型別時直接退出函式。
- MSG_EXCEPT:讀取除msgtyp以外的第一個訊息
- MSG_NOERROR:若待讀取的訊息尺寸比msgsz大,則只返回msgsz大小的部分,其餘部分丟棄
訊息佇列的屬性控制
IPC物件是一種永續性資源,如果沒有明確的刪除掉IPC物件,則IPC物件是不會自動從記憶體中消失的。使用者除了可以使用命令的方式刪除,也可以使用函式來刪除。
Linux系統中提供了一個名稱叫做msgctl的函式介面,使用者可以利用該函式實現獲取訊息佇列的屬性資訊、設定訊息佇列的屬性資訊、刪除訊息佇列等操作。
訊息佇列的刪除
-
透過shell命令:ipcrm
-
透過函式介面msgctl