linux下的進程間通訊

原帖發表在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下進程間通訊的幾種主要手段簡介: 安全


管道(Pipe)及有名管道(named pipe):管道可用於具備親緣關係進程間的通訊,有名管道克服了管道沒有名字的限制,所以,除具備管道所具備的功能外,它還容許無親緣關係進程間的通訊;
信號(Signal):信號是比較複雜的通訊方式,用於通知接受進程有某種事件發生,除了用於進程間通訊外,進程還能夠發送信號給進程自己;linux除 了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD爲 了實現可靠信號機制,又可以統一對外接口,用sigaction函數從新實現了signal函數);
報文(Message)隊列(消息隊列):消息隊列是消息的連接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程能夠向隊列中添加消息,被賦予讀權限的進程則能夠讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩衝區大小受限等缺點。
共享內存:使得多個進程能夠訪問同一塊內存空間,是最快的可用IPC形式。是針對其餘通訊機制運行效率較低而設計的。每每與其它通訊機制,如信號量結合使用,來達到進程間的同步及互斥。
信號量(semaphore):主要做爲進程間以及同一進程不一樣線程之間的同步手段。
套接口(Socket):更爲通常的進程間通訊機制,可用於不一樣機器之間的進程間通訊。起初是由Unix系統的BSD分支開發出來的,但如今通常能夠移植到其它類Unix系統上:Linux和System V的變種都支持套接字。

管道兩端可分別用描述字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,理解它們的讀寫規則是關鍵。

1、信號及信號來源

信號本質

信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一箇中斷請求能夠說是同樣的。信號是異步的,一個進程沒必要經過任何操做來等待信號的到達,事實上,進程也不知道信號到底何時到達。

信號是進程間通訊機制中惟一的異步通訊機制,能夠看做是異步通知,通知接收信號的進程有哪些事情發生了。信號機制通過POSIX實時擴展後,功能更增強大,除了基本通知功能外,還能夠傳遞附加信息。

信號來源

信號事件的發生有兩個來源:硬件來源(好比咱們按下了鍵盤或者其它硬件故障);軟件來源,最經常使用發送信號的系統函數是kill, raise, alarm和setitimer以及sigqueue函數,軟件來源還包括一些非法運算等操做。

 

3、進程對信號的響應

進程能夠經過三種方式來響應一個信號:(1)忽略信號,即對信號不作任何處理,其中,有兩個信號不能忽略:SIGKILL及SIGSTOP;(2)捕捉信 號。定義信號處理函數,當信號發生時,執行相應的處理函數;(3)執行缺省操做,Linux對每種信號都規定了默認操做,詳細狀況請參考[2]以及其它資 料。注意,進程對實時信號的缺省反應是進程終止。

Linux究竟採用上述三種方式的哪個來響應信號,取決於傳遞給相應API函數的參數。

1、信號生命週期

從信號發送到信號處理函數的執行完畢

對於一個完整的信號生命週期(從信號發送到相應的處理函數執行完畢)來講,能夠分爲三個重要的階段,這三個階段由四個重要事件來刻畫:信號誕生;信號在進程中註冊完畢;信號在進程中的註銷完畢;信號處理函數執行完畢。相鄰兩個事件的時間間隔構成信號生命週期的一個階段。

linux IPC快餐(轉) - xsh8637 - 第七天堂

 

消息隊列(也叫作報文隊列)可以克服早期unix通訊機制的一些缺點。做爲早期unix通訊機制之一的信號可以傳送的信息量有限,後來雖然POSIX 1003.1b在信號的實時性方面做了拓廣,使得信號在傳遞信息量方面有了至關程度的改進,可是信號這種通訊方式更像"即時"的通訊方式,它要求接受信號 的進程在某個時間範圍內對信號作出反應,所以該信號最多在接受信號進程的生命週期內纔有意義,信號所傳遞的信息是接近於隨進程持續的概念 (process-persistent),見 附錄 1;管道及有名管道及有名管道則是典型的隨進程持續IPC,而且,只能傳送無格式的字節流無疑會給應用程序開發帶來不便,另外,它的緩衝區大小也受到限制。

消息隊列就是一個消息的鏈表。能夠把消息看做一個記錄,具備特定的格式以及特定的優先級。對消息隊列有寫權限的進程能夠向中按照必定的規則添加新消息;對消息隊列有讀權限的進程則能夠從消息隊列中讀走消息。消息隊列是隨內核持續的(參見 附錄 1)。

 

3、消息隊列的限制

每一個消息隊列的容量(所能容納的字節數)都有限制,該值因系統不一樣而不一樣。

小結:

消息隊列與管道以及有名管道相比,具備更大的靈活性,首先,它提供有格式字節流,有利於減小開發人員的工做量;其次,消息具備類型,在實際應用中,可做爲 優先級使用。這兩點是管道以及有名管道所不能比的。一樣,消息隊列能夠在幾個進程間複用,而無論這幾個進程是否具備親緣關係,這一點與有名管道很類似;但 消息隊列是隨內核持續的,與有名管道(隨進程持續)相比,生命力更強,應用空間更大。

 


信號燈與其餘進程間通訊方式不大相同,它主要提供對進程間共享資源訪問控制機制。至關於內存中的標誌,進程能夠根據它斷定是否可以訪問某些共享資源,同時,進程也能夠修改該標誌。除了用於訪問控制外,還可用於進程同步。

1、信號燈概述

信號燈與其餘進程間通訊方式不大相同,它主要提供對進程間共享資源訪問控制機制。至關於內存中的標誌,進程能夠根據它斷定是否可以訪問某些共享資源,同時,進程也能夠修改該標誌。除了用於訪問控制外,還可用於進程同步。信號燈有如下兩種類型:


二值信號燈:最簡單的信號燈形式,信號燈的值只能取0或1,相似於互斥鎖。
注:二值信號燈可以實現互斥鎖的功能,但二者的關注內容不一樣。信號燈強調共享資源,只要共享資源可用,其餘進程一樣能夠修改信號燈的值;互斥鎖更強調進程,佔用資源的進程使用完資源後,必須由進程自己來解鎖。
計算信號燈:信號燈的值能夠取任意非負值(固然受內核自己的約束)。

5、信號燈的限制

一、 一次系統調用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調用應該注意的。

 


共享內存能夠說是最有用的進程間通訊方式,也是最快的IPC形式。兩個不一樣進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址 空間。進程A能夠即時看到進程B對共享內存中數據的更新,反之亦然。因爲多個進程共享同一塊內存區域,必然須要某種同步機制,互斥鎖和信號量均可以。

採用共享內存通訊的一個顯而易見的好處是效率高,由於進程能夠直接讀寫內存,而不須要任何數據的拷貝。對於像管道和消息隊列等通訊方式,則須要在內核和用 戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據[1]:一次從輸入文件到共享內存區,另外一次從共享內存區到輸出文件。實際上,進程之間在共享內存 時,並不老是讀寫少許數據後就解除映射,有新的通訊時,再從新創建共享內存區域。而是保持共享區域,直到通訊完畢爲止,這樣,數據內容一直保存在共享內存 中,並無寫回文件。共享內存中的內容每每是在解除映射時才寫回文件的。所以,採用共享內存的通訊方式效率是很是高的。

Linux的2.2.x內核支持多種共享內存方式,如mmap()系統調用,Posix共享內存,以及系統V共享內存。linux發行版本如Redhat 8.0支持mmap()系統調用及系統V共享內存,但還沒實現Posix共享內存,本文將主要介紹mmap()系統調用及系統V共享內存API的原理及應用。

 

2、mmap()及其相關係統調用

mmap()系統調用使得進程之間經過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程能夠向訪問普通內存同樣對文件進行訪問,沒必要再調用read(),write()等操做。

注:實際上,mmap()系統調用並非徹底爲了用於共享內存而設計的。它自己提供了不一樣於通常對普通文件的訪問方式,進程能夠像讀寫內存同樣對普通文件的操做。而Posix或系統V的共享內存IPC則純粹用於共享目的,固然mmap()實現共享內存也是其主要應用之一。

結論:

共享內存容許兩個或多個進程共享一給定的存儲區,由於數據不須要來回複製,因此是最快的一種進程間通訊機制。共享內存能夠經過mmap()映射普通文件 (特殊狀況下還能夠採用匿名映射)機制實現,也能夠經過系統V共享內存機制實現。應用接口和原理很簡單,內部機制複雜。爲了實現更安全通訊,每每還與信號 燈等同步機制共同使用。

共享內存涉及到了存儲管理以及文件系統等方面的知識,深刻理解其內部機制有必定的難度,關鍵還要牢牢抓住內核使用的重要數據結構。系統V共享內存是以文件 的形式組織在特殊文件系統shm中的。經過shmget能夠建立或得到共享內存的標識符。取得共享內存標識符後,要經過shmat將這個內存區映射到本進 程的虛擬地址空間。

一個套接口能夠看做是進程間通訊的端點(endpoint),每一個套接口的名字都是惟一的(惟一的含義是不言而喻的),其餘進程能夠發現、鏈接而且與之通 信。通訊域用來講明套接口通訊的協議,不一樣的通訊域有不一樣的通訊協議以及套接口的地址結構等等,所以,建立一個套接口時,要指明它的通訊域。比較常見的是 unix域套接口(採用套接口機制實現單機內的進程間通訊)及網際通訊域。

 

五、網絡編程中的其餘重要概念

下面列出了網絡編程中的其餘重要概念,基本上都是給出這些概念可以實現的功能,讀者在編程過程當中若是須要這些功能,可查閱相關概念。

(1)、I/O複用的概念

I/O複用提供一種能力,這種能力使得當一個I/O條件知足時,進程可以及時獲得這個信息。I/O複用通常應用在進程須要處理多個描述字的場合。它的一個 優點在於,進程不是阻塞在真正的I/O調用上,而是阻塞在select()調用上,select()能夠同時處理多個描述字,若是它所處理的全部描述字的 I/O都沒有處於準備好的狀態,那麼將阻塞;若是有一個或多個描述字I/O處於準備好狀態,則select()不阻塞,同時會根據準備好的特定描述字採起 相應的I/O操做。

(2)、Unix通訊域

前面主要介紹的是PF_INET通訊域,實現網際間的進程間通訊。基於Unix通訊域(調用socket時指定通訊域爲PF_LOCAL便可)的套接口可 以實現單機之間的進程間通訊。採用Unix通訊域套接口有幾個好處:Unix通訊域套接口一般是TCP套接口速度的兩倍;另外一個好處是,經過Unix通訊 域套接口能夠實如今進程間傳遞描述字。全部可用描述字描述的對象,如文件、管道、有名管道及套接口等,在咱們以某種方式獲得該對象的描述字後,均可以經過 基於Unix域的套接口來實現對描述字的傳遞。接收進程收到的描述字值不必定與發送進程傳遞的值一致(描述字是特定於進程的),可是特們指向內核文件表中 相同的項。

(3)、原始套接口

原始套接口提供通常套接口所不提供的功能:


原始套接口能夠讀寫一些用於控制的控制協議分組,如ICMPv4等,進而可實現一些特殊功能。
原始套接口能夠讀寫特殊的IPv4數據包。內核通常只處理幾個特定協議字段的數據包,那麼一些須要不一樣協議字段的數據包就須要經過原始套接口對其進行讀寫;
經過原始套接口能夠構造本身的Ipv4頭部,也是比較有意思的一點。

 

建立原始套接口須要root權限。

(4)、對數據鏈路層的訪問

對數據鏈路層的訪問,使得用戶能夠偵聽本地電纜上的全部分組,而不須要使用任何特殊的硬件設備,在linux下讀取數據鏈路層分組須要建立SOCK_PACKET類型的套接口,並須要有root權限。

(5)、帶外數據(out-of-band data)

若是有一些重要信息要馬上經過套接口發送(不通過排隊),請查閱與帶外數據相關的文獻。

(6)、多播

linux內核支持多播,可是在默認狀態下,多數linux系統都關閉了對多播的支持。所以,爲了實現多播,可能須要從新配置並編譯內核。具體請參考[4]及[2]。

結論:linux套接口編程的內容能夠說是極大豐富,同時它涉及到許多的網絡背景知識,有興趣的讀者可在[2]中找到比較系統而全面的介紹。

至此,本專題系列(linux環境進程間通訊)所有結束了。實際上,進程間通訊的通常意義一般指的是消息隊列、信號燈和共享內存,能夠是posix的,也能夠是SYS v的。本系列同時介紹了管道、有名管道、信號以及套接口等,是更爲通常意義上的進程間通訊機制。

相關文章
相關標籤/搜索