linux管道通訊

2022-08-01 00:21:21 字數 3995 閱讀 1031

管道是單向的位元組流,它將某個程序的標準輸出連線到另乙個程序的標準輸入。管道和有名管道是最早的程序間通訊機制之一,管道可用於具有親緣關係程序間的通訊,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係程序間的通訊。管道和有名管道的讀寫規則是在程式中應用它們的關鍵。 

管道相關的概念

在linux中管道是通過指向同乙個臨時的vfs inode的兩個file資料結構來實現的,此vfs

inode指向記憶體中的同乙個物理頁面。這就隱藏了讀寫管道和讀寫普通檔案的差別。管道是半雙工的,資料只能向乙個方向流動;需要雙方通訊時,需要建立起兩個管道;只能用於父子程序或者兄弟程序之間(具有親緣關係的程序);

管道對於管道兩端的程序而言,就是乙個檔案,但它不是普通的檔案,它不屬於某種檔案系統,單獨構成一種檔案系統,並且只存在與記憶體中。資料的讀出和寫入:乙個程序向管道中寫的內容被管道另一端的程序讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。

管道的建立:

#include

int pipe(int fd[2])

該函式建立的管道的兩端處於乙個程序中間,在實際應用中沒有太大意義,因此,乙個程序在由pipe()建立管道後,一般再fork乙個子程序,然後通過管道實現父子程序間的通訊(因此也不難推出,只要兩個程序中存在親緣關係,這裡的親緣關係指的是具有共同的祖先,都可以採用管道方式來進行通訊)。

管道的讀規則:

管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用於讀,由描述字fd[0]表示,稱其為管道讀端;另一端則只能用於寫,由描述字fd[1]來表示,稱其為管道寫端。如果試圖從管道寫端讀取資料,或者向管道讀端寫入資料都將導致錯誤發生。一般檔案的i/o函式都可以用於管道,如close、read、write等等。

從管道中讀取資料:如果管道的寫端不存在,則認為已經讀到了資料的末尾,讀函式返回的讀出位元組數為0;當管道的寫端存在時,如果請求的位元組數目大於pipe_buf,則返回管道中現有的資料位元組數,如果請求的位元組數目不大於pipe_buf,則返回管道中現有資料位元組數(此時,管道中資料量小於請求的資料量);或者返回請求的位元組數(此時,管道中資料量不小於請求的資料量)。管道寫端關閉後,寫入的資料將一直存在,直到讀出為止。

管道的寫規則:

向管道中寫入資料:向管道中寫入資料時,linux將不保證寫入的原子性,管道緩衝區一有空閒區域,寫程序就會試圖向管道寫入資料。如果讀程序不讀走管道緩衝區中的資料,那麼寫操作將一直阻塞。

注:只有在管道的讀端存在時,向管道中寫入資料才有意義。否則,向管道中寫入資料的程序將收到核心傳來的sifpipe訊號,應用程式可以處理該訊號,也可以忽略(預設動作則是應用程式終止)。對管道的寫規則的驗證1:寫端對讀端存在的依賴性

在向管道寫入資料時,至少應該存在某乙個程序,其中管道讀端沒有被關閉,否則就會出現錯誤(管道斷裂,程序收到了sigpipe訊號,預設動作是程序終止)對管道的寫規則的驗證2:linux不保證寫管道的原子性驗證

寫入管道的資料量大於4096位元組時,緩衝區的空閒空間將被寫入資料(補齊),直到寫完所有資料為止,如果沒有程序讀資料,則一直阻塞。

管道的侷限性 

只支援單向資料流;

只能用於具有親緣關係的程序之間;

沒有名字;

管道的緩衝區是有限的(管道制存在於記憶體中,在管道建立時,為緩衝區分配乙個頁面大小);

管道所傳送的是無格式位元組流,這就要求管道的讀出方和寫入方必須事先約定好資料的格式,比如多少位元組算作乙個訊息(或命令、或記錄)等等。

有名管道相概念 fifo

從名字就可以看出來它是支援先進先出的原則的。管道應用的乙個重大限制是它沒有名字,因此,只能用於具有親緣關係的程序間通訊,在有名管道(named

pipe或fifo)提出後,該限制得到了克服。fifo不同於管道之處在於它提供乙個路徑名與之關聯,以fifo的檔案形式存在於檔案系統中。這樣,即使與fifo的建立程序不存在親緣關係的程序,只要可以訪問該路徑,就能夠彼此通過fifo相互通訊(能夠訪問該路徑的程序以及fifo的建立程序之間),因此,通過fifo不相關的程序也能交換資料。值得注意的是,fifo嚴格遵循先進先出(first

in first

out),對管道及fifo的讀總是從開始處返回資料,對它們的寫則把資料新增到末尾。它們不支援諸如lseek()等檔案定位操作。

有名管道的建立

#include

#include

int mkfifo(const char * pathname, mode_t mode)

該函式的第乙個引數是乙個普通的路徑名,也就是建立後fifo的名字。第二個引數與開啟普通檔案的open()函式中的mode

引數相同。如果mkfifo的第乙個引數是乙個已經存在的路徑名時,會返回eexist錯誤,所以一般典型的呼叫**首先會檢查是否返回該錯誤,如果確實返回該錯誤,那麼只要呼叫開啟fifo的函式就可以了。一般檔案的i/o函式都可以用於fifo,如close、read、write等等。

fifo的開啟規則:

有名管道比管道多了乙個開啟操作:open。如果當前開啟操作是為讀而開啟fifo時,若已經有相應程序為寫而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為寫而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,成功返回(當前開啟操作沒有設定阻塞標誌)。

如果當前開啟操作是為寫而開啟fifo時,如果已經有相應程序為讀而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為讀而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,返回enxio錯誤(當前開啟操作沒有設定阻塞標誌)。對開啟規則的驗證參見附2。

有名管道的讀規則 

約定:如果乙個程序為了從fifo中讀取資料而阻塞開啟fifo,那麼稱該程序內的讀操作為設定了阻塞標誌的讀操作。

如果有程序寫開啟fifo,且當前fifo內沒有資料,則對於設定了阻塞標誌的讀操作來說,將一直阻塞。對於沒有設定阻塞標誌讀操作來說則返回-1,當前errno值為eagain,提醒以後再試。

對於設定了阻塞標誌的讀操作說,造成阻塞的原因有兩種:當前fifo內有資料,但有其它程序在讀這些資料;另外就是fifo內沒有資料。解阻塞的原因則是fifo中有新的資料寫入,不論信寫入資料量的大小,也不論讀操作請求多少資料量。

讀開啟的阻塞標誌只對本程序第乙個讀操作施加作用,如果本程序內有多個讀操作序列,則在第乙個讀操作被喚醒並完成讀操作後,其它將要執行的讀操作將不再阻塞,即使在執行讀操作時,fifo中沒有資料也一樣(此時,讀操作返回0)。如果沒有程序寫開啟fifo,則設定了阻塞標誌的讀操作會阻塞。

注:如果fifo中有資料,則設定了阻塞標誌的讀操作不會因為fifo中的位元組數小於請求讀的位元組數而阻塞,此時,讀操作會返回fifo中現有的資料量。

有名管道的寫規則 

約定:如果乙個程序為了向fifo中寫入資料而阻塞開啟fifo,那麼稱該程序內的寫操作為設定了阻塞標誌的寫操作。對於設定了阻塞標誌的寫操作:當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。如果此時管道空閒緩衝區不足以容納要寫入的位元組數,則進入睡眠,直到當緩衝區中能夠容納要寫入的位元組數時,才開始進行一次性寫操作。

當要寫入的資料量大於pipe_buf時,linux將不再保證寫入的原子性。fifo緩衝區一有空閒區域,寫程序就會試圖向管道寫入資料,寫操作在寫完所有請求寫的資料後返回。

對於沒有設定阻塞標誌的寫操作:

當要寫入的資料量大於pipe_buf時,linux將不再保證寫入的原子性。在寫滿所有fifo空閒緩衝區後,寫操作返回。

當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。如果當前fifo空閒緩衝區能夠容納請求寫入的位元組數,寫完後成功返回;如果當前fifo空閒緩衝區不能夠容納請求寫入的位元組數,則返回eagain錯誤,提醒以後再寫。

小結:管道常用於兩個方面:(1)在shell中時常會用到管道(作為輸入輸入的重定向),在這種應用方式下,管道的建立對於使用者來說是透明的;(2)用於具有親緣關係的程序間通訊,使用者自己建立管道,並完成讀寫操作。

fifo可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關係的程序同樣可以採用先進先出的通訊機制進行通訊。管道和fifo的資料是位元組流,應用程式之間必須事先確定特定的傳輸"協議",採用傳播具有特定意義的訊息。要靈活應用管道及fifo,理解它們的讀寫規則是關鍵。

Linux 管道通訊

一 定義 管道是單向的 先進先出的。它將乙個程式的輸入和另乙個程式的輸出連線起來。資料被乙個程序讀出後,將被從管道中刪除。分為無名和有名管道兩種。前者用於父程序和子程序間的通訊,後者用於同一系統的兩個程序間通訊。二 無名管道 int pipe int fd 2 其中,fd 0 用於讀管道,fd 1 ...

Linux管道通訊

現在在linux 中使用較多的程序間通訊方式主要有以下幾種。1 管道 pipe 及有名管道 named pipe 管道可用於具有親緣關係程序間的通訊,有名管道,除具有管道所具有的功能外,它還允許無親緣關係程序間的通訊。2 訊號 signal 訊號是在軟體層次上對中斷機制的一種模擬,它是比較複雜的通訊...

linux 管道通訊

無名管道 1 管道是半雙工的,只能支援資料的單向流動 兩程序間需要通訊時需要建立起兩個管道 2 使用無名管道通訊的程序必須擁有公共祖先程序 pipe 1 標頭檔案 include 2 定義函式 int pipe int filedes 2 3 函式說明 pipe 會建立管道,並將檔案描述詞由引數fi...