Linux程序間通訊IPC的幾種方式簡介
Linux程序通訊的源頭
linux下的程序通訊手段基本上是從Unix平臺上的程序通訊手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T(原為American Telephone & Telegraph的縮寫,也是中文譯名美國電話電報公司由來)的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟體釋出中心)在程序間通訊方面的側重點有所不同。前者對Unix早期的程序間通訊手段進行了系統的改進和擴充,形成了“system V IPC”,通訊程序侷限在單個計算機內;後者則跳過了該限制,形成了基於套介面(socket)的程序間通訊機制
最初Unix IPC包括:管道、FIFO、訊號。
System V IPC包括:System V訊息佇列、System V訊號燈、System V共享記憶體區。
Posix IPC包括: Posix訊息佇列、Posix訊號燈、Posix共享記憶體區。
有兩點需要簡單說明一下:1)由於Unix版本的多樣性,電子電氣工程協會(IEEE)開發了一個獨立的Unix標準,這個新的ANSI Unix標準被稱為計算機環境的可移植性作業系統介面(Portable Operating System Interface,PSOIX)。現有大部分Unix和流行版本都是遵循POSIX標準的
linux 所支援的各種IPC手段,在本文接下來的討論中,為了避免概念上的混淆,在儘可能少提及Unix的各個版本的情況下,所有問題的討論最終都會歸結到Linux環境下的程序間通訊上來。並且,對於Linux所支援通訊手段的不同實現版本(如對於共享記憶體來說,有Posix共享記憶體區以及System V共享記憶體區兩個實現版本),將主要介紹Posix API。
linux下程序間通訊的幾種主要手段
1)管道(Pipe)及有名管道(named pipe,FIFO)
匿名管道是Linux支援的最初Unix IPC形式之一,具有以下特點:
- 管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;STREAMS管道是一個雙向(全雙工)管道,單個STREAMS管道就能向父、子程序提供雙向資料流。Solaris支援STREAMS管道,Linux的可選附加包也提供了STREAMS管道。
- 只能用於父子程序或者兄弟程序之間(具有親緣關係的程序);
- 單獨構成一種獨立的檔案系統:管道對於管道兩端的程序而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,而是自立門戶,單獨構成一種檔案系統,並且只存在與記憶體中。
- 資料的讀出和寫入:一個程序向管道中寫的內容被管道另一端的程序讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。
兩者的不同點:
(1)匿名管道它沒有名字,只能用於具有親緣關係程序間的通訊。有名管道FIFO克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係程序間的通訊。
(2)匿名管道對於管道兩端的程序而言是一個檔案,但不是Linux某種型別的檔案、不屬於某個檔案系統,而且僅存在於記憶體中;pipe()函式打開了兩個檔案描述符,分別用於讀寫。有名管道提供一個路徑名與之關聯,是linux檔案型別的一種,因FIFO檔案形式存在於檔案系統中。
相同點:
(1)管道和FIFO的資料是位元組流,應用程式之間必須事先確定特定的傳輸"協議",採用傳播具有特定意義的訊息。
(2)單向(半雙工)資料流。
(3)系統對管道和FIFO的兩個限制OPEN_MAX(一個程序任意時刻開啟的最大描述符數)、PIPI_BUF(可原子地寫往一個管道或FIFO的最大資料量,posix要求至少512)。
4)都是隨程序持續的IPC(IPC物件一直存在到開啟該物件的最後一個程序關閉該物件為止。)
管道常用於兩個方面:
(1)在shell中時常會用到管道(作為輸入輸入的重定向),在這種應用方式下,管道的建立對於使用者來說是透明的;
(2)用於具有親緣關係的程序間通訊,使用者自己建立管道,並完成讀寫操作。
2)Unix域協議
參考文章:UNIX域協議
Unix域協議並不是一個實際的協議族,而是在單個主機上執行客戶/伺服器通訊的一種方法,所使用的API就是在不同主機上執行客戶/伺服器通訊所用的API(套接字API)。
Unix域套接字僅僅複製資料,並不執行協議處理,不需要新增或刪除網路報頭,無需計算校驗和,不要產生順序號,無需傳送確認報文。Unix域套接字提供流和資料報兩種介面。Unix域資料報服務是可靠的,既不會丟失訊息也不會傳遞出錯。它是套接字和管道之間的混合物。
使用Unix域套接字的理由:
(1)Unix域套接字往往比通訊兩端位於同一主機的TCP套接字快一倍(TCPv3)。Unix域套接字僅僅複製資料,並不執行協議處理,不需要新增或刪除網路報頭,無需計算校驗和,不要產生順序號,無需傳送確認報文。
(2)可用於在同一臺主機的不同程序之間傳遞描述符。
(3)Unix域套接字較新的實現把客戶的憑證(使用者ID和組ID)提供給伺服器,從而提供了額外的安全檢查措施。
為了建立一對非命名的、相互連線的UNIX域套接字,使用者可以使用它們面向網路的域套接字介面,也可以使用socketpair函式。
3)訊號(Signal)
訊號是比較複雜的通訊方式,用於通知接受程序有某種事件發生,除了用於程序間通訊外,程序還可以傳送訊號給程序本身;linux除了支援Unix早期訊號語義函式signal外,還支援語義符合Posix.1標準的訊號函式sigaction(實際上,該函式是基於BSD的,BSD為了實現可靠訊號機制,又能夠統一對外介面,用sigaction函式重新實現了signal函式)。sigaction包含了訊號產生的相關資訊。
4)訊息佇列
訊息佇列是訊息的連結表,包括Posix訊息佇列和system V訊息佇列。有足夠許可權的程序可以向佇列中新增訊息,被賦予讀許可權的程序則可以讀走佇列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。而且訊息佇列是隨核心持續的(IPC物件會一直存在,直到核心重啟或顯示刪除該物件為止)。
5)共享記憶體
參考文章:程序通訊方式:共享記憶體區
mmap:Linux環境程序間通訊(五): 共享記憶體(上)
System V共享記憶體: Linux環境程序間通訊(五): 共享記憶體(下)
使得多個程序可以訪問同一塊記憶體空間,是最快的可用IPC形式。是針對其他通訊機制執行效率較低而設計的。往往與其它通訊機制,如與訊號量結合使用,來達到程序間的同步及互斥。
6)訊號量(semaphore)
主要作為程序間以及同一程序不同執行緒之間的同步手段。
各種同步方式:
執行緒同步的幾種方式:參考文章:程序同步和執行緒同步
7)套介面(Socket)
更為一般的程序間通訊機制,可用於不同機器之間的程序間通訊。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支援套接字。