1. 程式人生 > >Linux程序間通訊IPC的幾種方式簡介

Linux程序間通訊IPC的幾種方式簡介

Linux程序通訊的源頭

      linux下的程序通訊手段基本上是從Unix平臺上的程序通訊手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T(原為American Telephone & Telegraph的縮寫,也是中文譯名美國電話電報公司由來)的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟體釋出中心)在程序間通訊方面的側重點有所不同。前者對Unix早期的程序間通訊手段進行了系統的改進和擴充,形成了“system V IPC”,通訊程序侷限在單個計算機內;後者則跳過了該限制,形成了基於套介面(socket)的程序間通訊機制

。Linux則把兩者繼承了下來。

       最初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從一開始就遵循POSIX標準;2)BSD並不是沒有涉足單機內的程序間通訊(socket本身就可以用於單機內的程序間通訊)。事實上,很多Unix版本的單機IPC留有BSD的痕跡,如4.4BSD支援的匿名記憶體對映、4.3+BSD對可靠訊號語義的實現等等。

        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的變種都支援套接字。