轉自:http://blog.csdn.net/Xiejingfa/article/details/50819660
進程間通信麻捻,英文又稱作IPC(InterProcess Communication)就是在不同的進程之間交換信息丛楚。我們知道,進程的用戶是相空間互獨立的周循,不能相互訪問拭卿,所以為了使得進程間可以相互通信擒抛,操作系統(tǒng)需要提供一種介質使通信雙方都可以訪問牧抵。類似這樣的介質有很多灭袁,比如磁盤上的文件,我們只要協(xié)調(diào)好進程訪問文件的順序洞豁,一個進程先“寫”盐固,一個進程后“讀”,這樣族跛,兩者就可以相互交換信息了闰挡。又比如我們經(jīng)常使用的數(shù)據(jù)庫锐墙,也可以作為信息交換的媒介礁哄。但是這些通信手段效率都太低了,需要在系統(tǒng)級別提供高效的進程間通信手段溪北。今天我們就來介紹一種最古老的進程間通信方式 – 管道桐绒。
1、什么是管道之拨?
如果你熟悉Linux系統(tǒng)茉继,一定不會對管道感到陌生。在Linux系統(tǒng)中蚀乔,我們經(jīng)常通過符號“|”來使用管道烁竭,用以連接兩個或多個命令。那管道是什么吉挣?實際上派撕,管道是進程與進程間的數(shù)據(jù)流通道,它使得數(shù)據(jù)可以以一種“流”的形式在進程間流動睬魂。管道也是Unix/Linux系統(tǒng)中一種最常見的進程間通信方式终吼,它在兩個通信進程之間實現(xiàn)一個數(shù)據(jù)流的通道從而進行信息傳遞。管道通信具有以下特點:
1氯哮,管道是沒有名字的际跪,因此有稱為匿名管道。它在系統(tǒng)中是沒有實名的,不能在文件系統(tǒng)中看到管道姆打。
2良姆,在大多數(shù)系統(tǒng)中,管道通信是半雙工的穴肘,也就是說數(shù)據(jù)只能在一個方向上流動歇盼。
3,管道中傳送的是無格式的字節(jié)流评抚。
4豹缀,管道的緩沖區(qū)是有限的,它的大小在include/linux/limits.h中由PIPE_BUF定義慨代。
5邢笙,管道只能用于具有親緣關系的進程間進行通信,如父子進程或者兄弟進程侍匙。
2氮惯、管道的創(chuàng)建
Linux下管道是通過pipe函數(shù)創(chuàng)建的,函數(shù)原型如下:
#include <unistd.h>
intpipe(intpipefd[2]);// 若成功則返回0想暗,出錯則返回-1
其中參數(shù)pipefd[2]是一個長度為2的文件描述符數(shù)組妇汗,pipefd[0]是讀端,pipefd[1]是寫端说莫。
管道的關閉則使用close函數(shù)杨箭。
#include <unistd.h>
intclose(intfd);
管道關閉時,需要將pipefd[0]和pipefd[1]都關閉掉储狭。
我們先用一段代碼演示一下管道的創(chuàng)建:
??? 在上面的例子中互婿,我們使用pipe()函數(shù)創(chuàng)建了一個管道。到這里你可能會感到奇怪:不是說管道是進程間通信的方式嗎辽狈?在單個進程中創(chuàng)建管道慈参,然后從一段寫入從另一端讀出有什么意義?下面我們重點講解一下管道如何實現(xiàn)進程間通信刮萌。
3驮配、管道的讀寫
??? 正如你所想的,在單個進程中的創(chuàng)建管道幾乎沒有意義着茸。前面我們說過管道只能用于父子進程或者兄弟進程間進行通信壮锻,通常我們先創(chuàng)建pipe,接著調(diào)用fork函數(shù)元扔,從而創(chuàng)建從父子進程或者兄弟進程間的ipc通道躯保。
??? 為什么這樣就能創(chuàng)建進程通信的管道呢?其中的功臣就是fork函數(shù)澎语。fork函數(shù)創(chuàng)建出來的子進程是父進程的一個拷貝途事,子進程從父進程中得到數(shù)據(jù)段和堆棧段的拷貝验懊。這樣,父子都擁有事先創(chuàng)建管道的文件描述符尸变,都可以往管道中讀寫信息义图。一般用于文件的IO函數(shù)如read、write等都可以用于管道的讀寫召烂。
???? 經(jīng)過fork函數(shù)調(diào)用之后碱工,父子進程間存在兩種數(shù)據(jù)流向的管道:一個是從父進程到子進程的數(shù)據(jù)通道,另一個是從子進程到父進程的數(shù)據(jù)通道奏夫。管道只支持半雙工通信怕篷,所以我們必須關閉其中一個數(shù)據(jù)通道!酗昼!
??? 比如:如果你想建立一個父進程到子進程的數(shù)據(jù)通道廊谓,就要在父進程中關閉讀端,在子進程中關閉寫端麻削。
??? 通常蒸痹,利用pipe和fork的組合,我們可以構造父子進程或者兄弟進程間任意方向的的數(shù)據(jù)通道呛哟。
上面的例子演示了利用管道在父進程到子進程的通信叠荠,而管道在兄弟進程間通信則需要在父進程調(diào)用兩次fork函數(shù)創(chuàng)建兩個子進程,在兩個兄弟子進程中維護通信管道扫责。
4榛鼎、管道讀寫的規(guī)則
管道寫入的規(guī)則:程序向管道寫入數(shù)據(jù)時,如果緩沖區(qū)有空閑空間公给,寫進程立即向管道寫入數(shù)據(jù)借帘。如果緩沖區(qū)已滿蜘渣,那么寫操作就一直阻塞到讀進程讀走數(shù)據(jù)為止淌铐。
管道讀取的規(guī)則:如果請求的字節(jié)數(shù)大于PIPE_SIZE,則返回管道中現(xiàn)有的字節(jié)數(shù)蔫缸。如果請求的字節(jié)數(shù)不大于PIPE_SIZE腿准,則返回請求的字節(jié)數(shù)或現(xiàn)有數(shù)據(jù)的字節(jié)數(shù)(管道中的數(shù)據(jù)量小于請求的數(shù)據(jù)量)。
如果讀寫一端已經(jīng)被關閉的管道是呢拾碌?
如果讀一個寫端已經(jīng)被關閉的管道時吐葱,當所有的數(shù)據(jù)都被讀取后,read返回0校翔,表示文件結束弟跑。
如果寫一個讀端已經(jīng)被關閉的管道,則產(chǎn)生SIGPIPE信號防症。如果忽略該信號或從處理程序中返回后孟辑,write函數(shù)返回-1哎甲,并且errno被設置為EPIPE。