管道和有名管道是最早的程序間通訊機制之一,管道可用於具有親緣關係程序間的通訊,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係程序間的通訊。 認清管道和有名管道的讀寫規則是在程式中應用它們的關鍵,本文在詳細討論了管道和有名管道的通訊機制的基礎上,用例項對其讀寫規則進行了程式驗證,這樣做有利於增強讀者對讀寫規則的感性認識,同時也提供了應用範例。
管道概述及相關api應用
1.1 管道相關的關鍵概念
管道是linux支援的最初unix ipc形式之一,具有以下特點:
1.2管道的建立:
#include
int pipe(int fd[2])該函式建立的管道的兩端處於乙個程序中間,在實際應用中沒有太大意義,因此,乙個程序在由pipe()建立管道後,一般再fork乙個子程序,然後通過管道實現父子程序間的通訊(因此也不難推出,只要兩個程序中存在親緣關係,這裡的親緣關係指的是具有共同的祖先,都可以採用管道方式來進行通訊)。
1.3管道的讀寫規則:
管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用於讀,由描述字fd[0]表示,稱其為管道讀端;另一端則只能用於寫,由描述字fd[1]來表示,稱其為管道寫端。如果試圖從管道寫端讀取資料,或者向管道讀端寫入資料都將導致錯誤發生。一般檔案的i/o函式都可以用於管道,如close、read、write等等。
從管道中讀取資料:
向管道中寫入資料:
1.5管道的侷限性
管道的主要侷限性正體現在它的特點上:
2、 有名管道概述及相關api應用
2.1 有名管道相關的關鍵概念
管道應用的乙個重大限制是它沒有名字,因此,只能用於具有親緣關係的程序間通訊,在有名管道(named pipe或fifo)提出後,該限制得到了克服。fifo不同於管道之處在於它提供乙個路徑名與之關聯,以fifo的檔案形式存在於檔案系統中。這樣,即使與fifo的建立程序不存在親緣關係的程序,只要可以訪問該路徑,就能夠彼此通過fifo相互通訊(能夠訪問該路徑的程序以及fifo的建立程序之間),因此,通過fifo不相關的程序也能交換資料。值得注意的是,fifo嚴格遵循先進先出(first in first out),對管道及fifo的讀總是從開始處返回資料,對它們的寫則把資料新增到末尾。它們不支援諸如lseek()等檔案定位操作。
2.2有名管道的建立
#include
#include
int mkfifo(const char * pathname, mode_t mode)
該函式的第乙個引數是乙個普通的路徑名,也就是建立後fifo的名字。第二個引數與開啟普通檔案的open()函式中的mode 引數相同。如果mkfifo的第乙個引數是乙個已經存在的路徑名時,會返回eexist錯誤,所以一般典型的呼叫**首先會檢查是否返回該錯誤,如果確實返回該錯誤,那麼只要呼叫開啟fifo的函式就可以了。一般檔案的i/o函式都可以用於fifo,如close、read、write等等。
2.3有名管道的開啟規則
有名管道比管道多了乙個開啟操作:open。
fifo的開啟規則:
如果當前開啟操作是為讀而開啟fifo時,若已經有相應程序為寫而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為寫而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,成功返回(當前開啟操作沒有設定阻塞標誌)。
如果當前開啟操作是為寫而開啟fifo時,如果已經有相應程序為讀而開啟該fifo,則當前開啟操作將成功返回;否則,可能阻塞直到有相應程序為讀而開啟該fifo(當前開啟操作設定了阻塞標誌);或者,返回enxio錯誤(當前開啟操作沒有設定阻塞標誌)。
2.4有名管道的讀寫規則
從fifo中讀取資料:
約定:如果乙個程序為了從fifo中讀取資料而阻塞開啟fifo,那麼稱該程序內的讀操作為設定了阻塞標誌的讀操作。
注:如果fifo中有資料,則設定了阻塞標誌的讀操作不會因為fifo中的位元組數小於請求讀的位元組數而阻塞,此時,讀操作會返回fifo中現有的資料量。
向fifo中寫入資料:
約定:如果乙個程序為了向fifo中寫入資料而阻塞開啟fifo,那麼稱該程序內的寫操作為設定了阻塞標誌的寫操作。
對於設定了阻塞標誌的寫操作:
對於沒有設定阻塞標誌的寫操作:
當要寫入的資料量不大於pipe_buf時,linux將保證寫入的原子性。如果當前fifo空閒緩衝區能夠容納請求寫入的位元組數,寫完後成功返回;如果當前fifo空閒緩衝區不能夠容納請求寫入的位元組數,則返回eagain錯誤,提醒以後再寫;
不管寫開啟的阻塞標誌是否設定,在請求寫入的位元組數大於4096時,都不保證寫入的原子性。但二者有本質區別:
對於阻塞寫來說,寫操作在寫滿fifo的空閒區域後,會一直等待,直到寫完所有資料為止,請求寫入的資料最終都會寫入fifo;
而非阻塞寫則在寫滿fifo的空閒區域後,就返回(實際寫入的位元組數),所以有些資料最終不能夠寫入。
對於讀操作的驗證則比較簡單,不再討論。
2.5有名管道應用例項
在驗證了相應的讀寫規則後,應用例項似乎就沒有必要了。
小結:管道常用於兩個方面:(1)在shell中時常會用到管道(作為輸入輸入的重定向),在這種應用方式下,管道的建立對於使用者來說是透明的;(2)用於具有親緣關係的程序間通訊,使用者自己建立管道,並完成讀寫操作。
fifo可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關係的程序同樣可以採用先進先出的通訊機制進行通訊。
管道和fifo的資料是位元組流,應用程式之間必須事先確定特定的傳輸"協議",採用傳播具有特定意義的訊息。
要靈活應用管道及fifo,理解它們的讀寫規則是關鍵。
有名管道管道程式設計
linux程序和程序之間有多種通訊方式。linux程序間通訊的主要方式有 1 無名管道 2 有名管道 3 訊號 4 訊息佇列 5 共享記憶體 6 訊號量 7 套接字 管道操作是比較簡單的通訊方式,乙個程序往管道中寫入資料,另乙個程序從管道中讀出資料。管道包括無名管道和有名管道。前者只能用於父程序和子...
無名管道和有名管道
無名管道 無名管道建立 int pipe int filedis 2 當乙個管道建立時,它會建立兩個檔案描述符 filedis 0 用於讀管道,filedis 1 用於寫管道 管道用於不同程序間通訊。通常先建立乙個管道,再通過fork函式建立乙個子程序,該子程序會繼承父程序所建立的管道 有名管道 有...
管道 無名管道 和FIFO 有名管道
管道是最初的unixipc形式,但是因為管道沒有名字,所以它們只能用於有親緣關係的程序使用 進而有名管道 fifo 應運而生,有名管道有乙個路徑名與之關聯,所以允許無親緣關係的程序訪問同乙個fifo。以下具體介紹管道 管道的建立 管道由函式 int pipe int fd 2 建立,提供乙個單向資料...