天天看點

程序間通信(IPC)之————管道

    在Linux作業系統中,每個程序都有屬于自己的運作空間,空間記憶體放有資料和執行代碼,那麼不同的程序互相之間是如何進行資料和資訊的交換呢?Linux中提供了一種用于程序間通信(IPC-Inter Process Communication)最基本的機制——管道。

    在Linux系統中一切皆檔案,管道是一種特殊的檔案,它是在核心中開辟了一塊緩沖區,該緩沖區大小往往是固定的,Ubuntu中為65536也就2^16個位元組也就是32K。這裡值得提出的是,管道的通信是單向的,它提供了一個讀端和一個寫端,用函數pipe來建立,其傳回值調用成功傳回0,若失敗傳回-1:

程式間通信(IPC)之————管道

開辟了管道之後,它實作程序間通信的機制就可以如下圖所示:

程式間通信(IPC)之————管道

首先由一個父程序pipe出一個管道并得到其讀端和寫端的檔案描述符;

其次當父程序fork出一個子程序時,子程序從父程序那裡得到兩個檔案描述符指向同一管道

父程序關閉寫端,子程序關閉讀端,子程序向管道内寫入資料父程序就可以從中讀到,這樣就實作了程序間的通信。

示範代碼:

程式間通信(IPC)之————管道
程式間通信(IPC)之————管道

代碼中子程序每隔1秒向管道中寫入資料,父程序從管道的讀端讀取并輸出,整個代碼中隻有父程序在輸出,而子程序在寫入,是以實作了程序間的通信,但是使用管道時,需要注意下面四種情況:

當管道的寫端關閉,即寫端的引用計數為0,而讀端一直從管道内讀取資料,當将管道内資料全部都讀取完時,再次read就會傳回0,就像是讀到了檔案的末尾一樣。例:将上面程式中的子程序改為如下:

程式間通信(IPC)之————管道

當count小于5時關閉子程序的寫端,運作結果為:

程式間通信(IPC)之————管道

2. 當管道的寫端不關閉,但也不向管道内寫入資料,這時有程序從管道内讀取資料,當程序将管道内的   資料讀取完時,再次read就會阻塞,直到有資料寫入時才會再次讀取。将上例中子程序改為如下:

程式間通信(IPC)之————管道

當count等于5時,父程序已經讀取到了5條資料,這時不關閉子程序的寫端,但是讓子程序sleep上5秒,這時父程序再從管道中讀取資料時就會阻塞,5秒過後子程序再次向管道内寫入資料,父程序就可以正常從管道中取得資料了。

3. 當指向管道讀端的檔案描述符都關閉,即讀端引用計數為0,但仍然有程序向管道内寫入資料時,那   麼該程序就會收到一個SIGPIPE的信号,通常會導緻程序異常終止。将上例中的父程序改為如下:

程式間通信(IPC)之————管道

父程序中當count小于5時就将管道的讀端關閉,此時子程序仍然會向管道内寫入資料,在父程序内調用waitpid函數擷取子程序的退出碼,因為參數status是一個整型,其低八位是子程序異常退出時的狀态碼,而次第八位是正常終止的狀态碼,用status按位與0xff可以得到其低八位,運作程式可得到如下結果:

程式間通信(IPC)之————管道

子程序異常終止,其退出狀态碼為13,其代表就是SIGPIPE。

4. 當管道的讀端并沒有關閉,但沒有程序從管道内讀取資料,這時不斷地有程序向管道内寫入資料,當管道被寫滿時,再次write就會阻塞,直到有資料被讀取管道内有空地時會再次寫入。将上例中父子程序改為如下:

程式間通信(IPC)之————管道

将子程序改為死循環,記錄寫入次數,每次向管道内寫入1個位元組,同時讓父程序的讀端并不讀入資料,運作程式結果如下:

程式間通信(IPC)之————管道

當count加到65535時說明管道已寫滿不再寫入,等待讀端從管道内讀取資料之後才繼續寫入,是以可以知道管道的大小為65536個位元組,也就是32K。

    上面的各種分析中,雖然實作了程序間的資料交換,但可以注意到,這種通信機制隻适用于父子之間或者有血緣關系的程序之間,因為需要從父程序那裡繼承得到相同的檔案描述符來對同一個管道進行讀寫操作,雖然可以通信,但難免是有些限制的。

    為了解決這種限制,讓不同的程序不管有沒有血緣關系都可以通路同一個管道自由的進行通信,就有了另一種管道———命名管道(FIFO)。命名管道不同于上面所述的匿名管道的是,它是存在于系統中的一個檔案,任何程序隻要可以通路該檔案的路徑,就能夠通過FIFO進行互相通信。這裡要提出,FIFO總是按照先進先出的原則,即第一個寫入的資料總是第一個被讀出。

    用mkfifo函數建立一個命名管道:

程式間通信(IPC)之————管道

函數參數中,第一個為檔案的相對路徑或絕對路徑,表明在系統中建立一個管道檔案,第二個參數為檔案的權限資訊。

    建立好管道檔案之後,就可以使用了,因為是檔案,是以可以打開,在一個程式中打開檔案,如果以讀寫方式打開就不會阻塞,如果以隻讀方式打開就會阻塞直到有以寫方式打開此檔案為止,同樣,如果以隻寫方式打開就會阻塞直到有讀方式打開檔案為止。

程式示例:

程式間通信(IPC)之————管道

上面建立了兩個檔案client.c和server.c,在client.c中用mkfifo函數建立了一個在目前目錄下的一個隐藏檔案.tmp,然後以隻寫方式打開檔案,并且用write函數向檔案中寫入資料,然後再server.c程式中同樣打開.tmp檔案,此時因為檔案已經在client.c中被建立了,是以可以用隻讀方式打開,并用read函數從中擷取被寫入的資料,這樣就可以實作兩個程序間的通信,而不需要考慮程序之間是否有關系。

這裡需要提出的是,在設定管道檔案的權限時,需要考慮umask的影響。

運作client程式,再打開一個終端運作起來server,在client終端輸入想要輸入的内容,可以看見在server終端接收到,如此實作兩個程序間通信。

《完》

繼續閱讀