原帖發表在IBM的developerworks網站上,是一個系列的文章,做者鄭彥興,經過講解和例子演示了Linux中幾種IPC的使用方式,我以爲很好,在這裏作一個保留,能看完的話Linux IPC的基礎是沒有問題的了。
一)Linux環境進程間通訊(一)管道及有名管道
http://www.ibm.com/developerworks/cn/linux/l-ipc/part1/
二)Linux環境進程間通訊(二): 信號
上:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html
下:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html
三)Linux環境進程間通訊(三)消息隊列
http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/
四)Linux環境進程間通訊(四)信號燈
http://www.ibm.com/developerworks/cn/linux/l-ipc/part4/
五)Linux環境進程間通訊(五): 共享內存
上:http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html
下:http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index2.html html
六)Linux環境進程間通訊(六): socket linux
http://www.ibm.com/developerworks/cn/linux/l-ipc/ shell
============================================================================================== 編程
linux下進程間通訊的幾種主要手段簡介: 安全
管道兩端可分別用描述字fd[0]以及fd[1]來描述,須要注意的是,管道的兩端是固定了任務的。即一端只能用於讀,由描述字fd[0]表示,稱其爲管 道讀端;另外一端則只能用於寫,由描述字fd[1]來表示,稱其爲管道寫端。若是試圖從管道寫端讀取數據,或者向管道讀端寫入數據都將致使錯誤發生。通常文 件的I/O函數均可以用於管道,如close、read、write等等。 網絡
管道的主要侷限性正體如今它的特色上: 數據結構
管道應用的一個重大限制是它沒有名字,所以,只能用於具備親緣關係的進程間通訊,在有名管道(named pipe或FIFO)提出後,該限制獲得了克服。FIFO不一樣於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即 使與FIFO的建立進程不存在親緣關係的進程,只要能夠訪問該路徑,就可以彼此經過FIFO相互通訊(可以訪問該路徑的進程以及FIFO的建立進程之 間),所以,經過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀老是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操做。 異步
管道經常使用於兩個方面:(1)在shell中時常會用到管道(做爲輸入輸入的重定向),在這種應用方式下,管道的建立對於用戶來講是透明的;(2)用於具備親緣關係的進程間通訊,用戶本身建立管道,並完成讀寫操做。 socket
FIFO能夠說是管道的推廣,克服了管道無名字的限制,使得無親緣關係的進程一樣能夠採用先進先出的通訊機制進行通訊。 函數
管道和FIFO的數據是字節流,應用程序之間必須事先肯定特定的傳輸"協議",採用傳播具備特定意義的消息。
要靈活應用管道及FIFO,理解它們的讀寫規則是關鍵。
信號本質
信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一箇中斷請求能夠說是同樣的。信號是異步的,一個進程沒必要經過任何操做來等待信號的到達,事實上,進程也不知道信號到底何時到達。
信號是進程間通訊機制中惟一的異步通訊機制,能夠看做是異步通知,通知接收信號的進程有哪些事情發生了。信號機制通過POSIX實時擴展後,功能更增強大,除了基本通知功能外,還能夠傳遞附加信息。
信號來源
信號事件的發生有兩個來源:硬件來源(好比咱們按下了鍵盤或者其它硬件故障);軟件來源,最經常使用發送信號的系統函數是kill, raise, alarm和setitimer以及sigqueue函數,軟件來源還包括一些非法運算等操做。
進程能夠經過三種方式來響應一個信號:(1)忽略信號,即對信號不作任何處理,其中,有兩個信號不能忽略:SIGKILL及SIGSTOP;(2)捕捉信 號。定義信號處理函數,當信號發生時,執行相應的處理函數;(3)執行缺省操做,Linux對每種信號都規定了默認操做,詳細狀況請參考[2]以及其它資 料。注意,進程對實時信號的缺省反應是進程終止。
Linux究竟採用上述三種方式的哪個來響應信號,取決於傳遞給相應API函數的參數。
從信號發送到信號處理函數的執行完畢
對於一個完整的信號生命週期(從信號發送到相應的處理函數執行完畢)來講,能夠分爲三個重要的階段,這三個階段由四個重要事件來刻畫:信號誕生;信號在進程中註冊完畢;信號在進程中的註銷完畢;信號處理函數執行完畢。相鄰兩個事件的時間間隔構成信號生命週期的一個階段。
消息隊列(也叫作報文隊列)可以克服早期unix通訊機制的一些缺點。做爲早期unix通訊機制之一的信號可以傳送的信息量有限,後來雖然POSIX 1003.1b在信號的實時性方面做了拓廣,使得信號在傳遞信息量方面有了至關程度的改進,可是信號這種通訊方式更像"即時"的通訊方式,它要求接受信號 的進程在某個時間範圍內對信號作出反應,所以該信號最多在接受信號進程的生命週期內纔有意義,信號所傳遞的信息是接近於隨進程持續的概念 (process-persistent),見 附錄 1;管道及有名管道及有名管道則是典型的隨進程持續IPC,而且,只能傳送無格式的字節流無疑會給應用程序開發帶來不便,另外,它的緩衝區大小也受到限制。
消息隊列就是一個消息的鏈表。能夠把消息看做一個記錄,具備特定的格式以及特定的優先級。對消息隊列有寫權限的進程能夠向中按照必定的規則添加新消息;對消息隊列有讀權限的進程則能夠從消息隊列中讀走消息。消息隊列是隨內核持續的(參見 附錄 1)。
每一個消息隊列的容量(所能容納的字節數)都有限制,該值因系統不一樣而不一樣。
消息隊列與管道以及有名管道相比,具備更大的靈活性,首先,它提供有格式字節流,有利於減小開發人員的工做量;其次,消息具備類型,在實際應用中,可做爲 優先級使用。這兩點是管道以及有名管道所不能比的。一樣,消息隊列能夠在幾個進程間複用,而無論這幾個進程是否具備親緣關係,這一點與有名管道很類似;但 消息隊列是隨內核持續的,與有名管道(隨進程持續)相比,生命力更強,應用空間更大。
信號燈與其餘進程間通訊方式不大相同,它主要提供對進程間共享資源訪問控制機制。至關於內存中的標誌,進程能夠根據它斷定是否可以訪問某些共享資源,同時,進程也能夠修改該標誌。除了用於訪問控制外,還可用於進程同步。信號燈有如下兩種類型:
一、 一次系統調用semop可同時操做的信號燈數目SEMOPM,semop中的參數nsops若是超過了這個數目,將返回E2BIG錯誤。SEMOPM的大小特定與系統,redhat 8.0爲32。
二、 信號燈的最大數目:SEMVMX,當設置信號燈值超過這個限制時,會返回ERANGE錯誤。在redhat 8.0中該值爲32767。
三、 系統範圍內信號燈集的最大數目SEMMNI以及系統範圍內信號燈的最大數目SEMMNS。超過這兩個限制將返回ENOSPC錯誤。redhat 8.0中該值爲32000。
四、 每一個信號燈集中的最大信號燈數目SEMMSL,redhat 8.0中爲250。 SEMOPM以及SEMVMX是使用semop調用時應該注意的;SEMMNI以及SEMMNS是調用semget時應該注意的。SEMVMX同時也是semctl調用應該注意的。
採用共享內存通訊的一個顯而易見的好處是效率高,由於進程能夠直接讀寫內存,而不須要任何數據的拷貝。對於像管道和消息隊列等通訊方式,則須要在內核和用 戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據[1]:一次從輸入文件到共享內存區,另外一次從共享內存區到輸出文件。實際上,進程之間在共享內存 時,並不老是讀寫少許數據後就解除映射,有新的通訊時,再從新創建共享內存區域。而是保持共享區域,直到通訊完畢爲止,這樣,數據內容一直保存在共享內存 中,並無寫回文件。共享內存中的內容每每是在解除映射時才寫回文件的。所以,採用共享內存的通訊方式效率是很是高的。
Linux的2.2.x內核支持多種共享內存方式,如mmap()系統調用,Posix共享內存,以及系統V共享內存。linux發行版本如Redhat 8.0支持mmap()系統調用及系統V共享內存,但還沒實現Posix共享內存,本文將主要介紹mmap()系統調用及系統V共享內存API的原理及應用。
mmap()系統調用使得進程之間經過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程能夠向訪問普通內存同樣對文件進行訪問,沒必要再調用read(),write()等操做。
注:實際上,mmap()系統調用並非徹底爲了用於共享內存而設計的。它自己提供了不一樣於通常對普通文件的訪問方式,進程能夠像讀寫內存同樣對普通文件的操做。而Posix或系統V的共享內存IPC則純粹用於共享目的,固然mmap()實現共享內存也是其主要應用之一。
共享內存容許兩個或多個進程共享一給定的存儲區,由於數據不須要來回複製,因此是最快的一種進程間通訊機制。共享內存能夠經過mmap()映射普通文件 (特殊狀況下還能夠採用匿名映射)機制實現,也能夠經過系統V共享內存機制實現。應用接口和原理很簡單,內部機制複雜。爲了實現更安全通訊,每每還與信號 燈等同步機制共同使用。
共享內存涉及到了存儲管理以及文件系統等方面的知識,深刻理解其內部機制有必定的難度,關鍵還要牢牢抓住內核使用的重要數據結構。系統V共享內存是以文件 的形式組織在特殊文件系統shm中的。經過shmget能夠建立或得到共享內存的標識符。取得共享內存標識符後,要經過shmat將這個內存區映射到本進 程的虛擬地址空間。
一個套接口能夠看做是進程間通訊的端點(endpoint),每一個套接口的名字都是惟一的(惟一的含義是不言而喻的),其餘進程能夠發現、鏈接而且與之通 信。通訊域用來講明套接口通訊的協議,不一樣的通訊域有不一樣的通訊協議以及套接口的地址結構等等,所以,建立一個套接口時,要指明它的通訊域。比較常見的是 unix域套接口(採用套接口機制實現單機內的進程間通訊)及網際通訊域。
下面列出了網絡編程中的其餘重要概念,基本上都是給出這些概念可以實現的功能,讀者在編程過程當中若是須要這些功能,可查閱相關概念。
I/O複用提供一種能力,這種能力使得當一個I/O條件知足時,進程可以及時獲得這個信息。I/O複用通常應用在進程須要處理多個描述字的場合。它的一個 優點在於,進程不是阻塞在真正的I/O調用上,而是阻塞在select()調用上,select()能夠同時處理多個描述字,若是它所處理的全部描述字的 I/O都沒有處於準備好的狀態,那麼將阻塞;若是有一個或多個描述字I/O處於準備好狀態,則select()不阻塞,同時會根據準備好的特定描述字採起 相應的I/O操做。
前面主要介紹的是PF_INET通訊域,實現網際間的進程間通訊。基於Unix通訊域(調用socket時指定通訊域爲PF_LOCAL便可)的套接口可 以實現單機之間的進程間通訊。採用Unix通訊域套接口有幾個好處:Unix通訊域套接口一般是TCP套接口速度的兩倍;另外一個好處是,經過Unix通訊 域套接口能夠實如今進程間傳遞描述字。全部可用描述字描述的對象,如文件、管道、有名管道及套接口等,在咱們以某種方式獲得該對象的描述字後,均可以經過 基於Unix域的套接口來實現對描述字的傳遞。接收進程收到的描述字值不必定與發送進程傳遞的值一致(描述字是特定於進程的),可是特們指向內核文件表中 相同的項。
原始套接口提供通常套接口所不提供的功能:
建立原始套接口須要root權限。
對數據鏈路層的訪問,使得用戶能夠偵聽本地電纜上的全部分組,而不須要使用任何特殊的硬件設備,在linux下讀取數據鏈路層分組須要建立SOCK_PACKET類型的套接口,並須要有root權限。
若是有一些重要信息要馬上經過套接口發送(不通過排隊),請查閱與帶外數據相關的文獻。
linux內核支持多播,可是在默認狀態下,多數linux系統都關閉了對多播的支持。所以,爲了實現多播,可能須要從新配置並編譯內核。具體請參考[4]及[2]。
結論:linux套接口編程的內容能夠說是極大豐富,同時它涉及到許多的網絡背景知識,有興趣的讀者可在[2]中找到比較系統而全面的介紹。
至此,本專題系列(linux環境進程間通訊)所有結束了。實際上,進程間通訊的通常意義一般指的是消息隊列、信號燈和共享內存,能夠是posix的,也能夠是SYS v的。本系列同時介紹了管道、有名管道、信號以及套接口等,是更爲通常意義上的進程間通訊機制。