管道與消息

管道和消息隊列的區別
管道(PIPE)

管道通信方式的中間介質是文件,通常稱這種文件爲管道文件。兩個進程利用管道文件進行通信時,一個進程爲寫進程,另一個進程爲讀進程。寫進程通過寫端(發送端)往管道文件中寫入信息;讀進程通過讀端(接收端)從管道文件中讀取信息。兩個進程協調不斷地進行寫、讀,便會構成雙方通過管道傳遞信息的流水線。

管道分爲匿名管道和命名管道。
(1)匿名管道:管道是半雙工的,數據只能單向通信;需要雙方通信時,需要建立起兩個管道;只能用於父子進程或者兄弟進程之間(具有親緣關係的進程)。
(2)命名管道:可在同一臺計算機的不同進程之間或在跨越一個網絡的不同計算機的不同進程之間,支持可靠的、單向或雙向的數據通信

  不同於匿名管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即使與FIFO的創建進程不存在親緣關係的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之間),因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。

 利用系統調用pipe()創建一個無名管道文件,通常稱爲無名管道或PIPE;利用系統調用mknod()創建一個命名管道文件,通常稱爲有名管道或FIFO。PIPE是一種非永久性的管道通信機構,當它訪問的進程全部終止時,它也將隨之被撤消;它也不能用於不同族系的進程之間的通信。而FIFO是一種永久的管道通信機構,它可以彌補PIPE的不足。管道文件被創建後,使用open()將文件進行打開,然後便可對它進行讀寫操作,通過系統調用write()和read()來實現。通信完畢後,可使用close()將管道文件關閉。因爲匿名管道的文件是內存中的特殊文件,而且是不可見的,命名管道的文件是硬盤上的設備文件,是可見的。

**消息隊列****(message queue)******
消息隊列與命名管道類似,但少了打開和關閉管道方面的複雜性。使用消息隊列並未解決我們在使用命名管道時遇到的一些問題,如管道滿時的阻塞問題。消息隊列提供了一種在兩個不相關進程間傳遞數據的簡單有效的方法。與命名管道相比:消息隊列的優勢在於,它獨立於發送和接收進程而存在,這消除了在同步命名管道的打開和關閉時可能產生的一些困難。消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。而且,每個數據塊被認爲含有一個類型,接收進程可以獨立地接收含有不同類型值的數據塊。

優點:
A. 我們可以通過發送消息來幾乎完全避免命名管道的同步和阻塞問題。
B. 我們可以用一些方法來提前查看緊急消息。

缺點:
A. 與管道一樣,每個數據塊有一個最大長度的限制。
B. 系統中所有隊列所包含的全部數據塊的總長度也有一個上限。

Linux系統中有兩個宏定義:
MSGMAX, 以字節爲單位,定義了一條消息的最大長度。
MSGMNB, 以字節爲單位,定義了一個隊列的最大長度。

限制:
由於消息緩衝機制中所使用的緩衝區爲共用緩衝區,因此使用消息緩衝機制傳送數據時,兩通信進程必須滿足如下條件。
(1)在發送進程把寫入消息的緩衝區掛入消息隊列時,應禁止其他進程對消息隊列的訪問,否則,將引起消息隊列的混亂。同理,當接收進程正從消息隊列中取消息時,也應禁止其他進程對該隊列的訪問。
(2)當緩衝區中無消息存在時,接收進程不能接收任何消息;而發送進程是否可以發送消息,則只由發送進程是否能夠申請緩衝區決定。

=============================================================================================
共享內存比管道和消息隊列效率高的原因
共享內存是進程間通信中最簡單的方式之一。共享內存允許兩個或更多進程訪問同一塊內存,就如同 malloc() 函數向不同進程返回了指向同一個物理內存區域的指針。當一個進程改變了這塊地址中的內容的時候,其它進程都會察覺到這個更改。
因爲所有進程共享同一塊內存,共享內存在各種進程間通信方式中具有最高的效率。訪問共享內存區域和訪問進程獨有的內存區域一樣快,並不需要通過系統調用或者其它需要切入內核的過程來完成。同時它也避免了對數據的各種不必要的複製。 因爲系統內核沒有對訪問共享內存進行同步,您必須提供自己的同步措施。例如,在數據被寫入之前不允許進程從共享內存中讀取信息、不允許兩個進程同時向同一個共享內存地址寫入數據等。解決這些問題的常用方法是通過使用信號量進行同步。
共享內存塊提供了在任意數量的進程之間進行高效雙向通信的機制。每個使用者都可以讀取寫入數據,但是所有程序之間必須達成並遵守一定的協議,以防止諸如在讀取信息之前覆寫內存空間等競爭狀態的出現。不幸的是,Linux無法嚴格保證提供對共享內存塊的獨佔訪問,甚至是在您通過使用IPC_PRIVATE創建新的共享內存塊的時候也不能保證訪問的獨佔性。 同時,多個使用共享內存塊的進程之間必須協調使用同一個鍵值。

   共享內存區是最快的可用IPC形式,一旦這樣的內存區映射到共享它的進程的地址空間,這些進程間數據的傳遞就不再通過執行任何進入內核的系統調用來傳遞彼此的數據,節省了時間。       共享內存和消息隊列,FIFO,管道傳遞消息的區別:       ——消息隊列,FIFO,管道的消息傳遞方式一般爲          1:服務器得到輸入          2:通過管道,消息隊列寫入數據,通常需要從進程拷貝到內核。          3:客戶從內核拷貝到進程          4:然後再從進程中拷貝到輸出文件      上述過程通常要經過4次拷貝,才能完成文件的傳遞。       ——共享內存只需要           1:從輸入文件到共享內存區           2:從共享內存區輸出到文件

上述過程不涉及到內核的拷貝,所以花的時間較少。



作者:WB莫遙燚
鏈接:https://www.jianshu.com/p/6153195b1030
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章