原文地址: FIFO有時(shí)被稱為命名管道。管道只能由相關(guān)進(jìn)程使用,這些相關(guān)進(jìn)程的共同祖先進(jìn)程創(chuàng)建了管道。但是,通過FIFO,不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。
FIFO是一種文件類型(參考)。stat結(jié)構(gòu)()成員的編碼指明文件是否是FIFO類型。可以用()宏對(duì)此進(jìn)行測(cè)試。
創(chuàng)建FIFO類似于創(chuàng)建文件。確實(shí),F(xiàn)IFO的路徑名存在于文件系統(tǒng)中。
#includeint mkfifo(const char *pathname, mode_t mode); 返回值:若成功則返回0,若出錯(cuò)則返回-1
函數(shù)中mode參數(shù)的規(guī)格說明與open函數(shù)中的mode相同(見,具體的mode取值見)。新FIFO的用戶和組的所有權(quán)規(guī)則與中所述的相同。
一旦已經(jīng)用創(chuàng)建了一個(gè)FIFO,就可用open打開它。其實(shí),一般的文件I/O函數(shù)(close、read、write、等)都可用于FIFO。
應(yīng)用程序可以用mknod函數(shù)創(chuàng)建FIFO。POSIX.1原先并沒有包括mknod函數(shù),它首先提出了。mknod現(xiàn)在已包括在XSI擴(kuò)展中。在大多數(shù)系統(tǒng)中,調(diào)用mknod創(chuàng)建FIFO。
POSIX.1也包括了對(duì)(1)命令的支持。于是,用一條shell命令就可以創(chuàng)建一個(gè)FIFO,然后用一般的shell I/O重定向?qū)ζ溥M(jìn)行訪問。
當(dāng)打開一個(gè)FIFO時(shí),非阻塞標(biāo)志()產(chǎn)生下列影響:
類似于管道,若用write寫一個(gè)尚無進(jìn)程為讀而打開的FIFO,則產(chǎn)生信號(hào)。若某個(gè)FIFO的最后一個(gè)寫進(jìn)程關(guān)閉了該FIFO,則將為該FIFO的讀進(jìn)程產(chǎn)生一個(gè)文件結(jié)束標(biāo)志。
一個(gè)給定的FIFO有多個(gè)寫進(jìn)程是很常見的。這就意味著如果不希望多個(gè)進(jìn)程所寫的數(shù)據(jù)互相穿插,則需考慮原子寫操作。正如對(duì)于管道一樣,常量說明了可被原子地寫到FIFO的最大數(shù)據(jù)量。
FIFO有下面兩種用途:
(1)FIFO由shell命令使用以便將數(shù)據(jù)從一條管道線傳送到另一條,為此無需創(chuàng)建中間臨時(shí)文件。
(2)FIFO用于客戶進(jìn)程-服務(wù)器進(jìn)程應(yīng)用程序中,以在客戶進(jìn)程和服務(wù)器進(jìn)程之間傳送數(shù)據(jù)。
我們各用一個(gè)例子來說明這兩種用途。
實(shí)例:用FIFO復(fù)制輸出流
FIFO可被用于復(fù)制串行管道命令之間的輸出流,于是也就不需要寫數(shù)據(jù)到中間磁盤文件中(類似于使用管道以避免中間磁盤文件)。管道只能用于進(jìn)程間的線性連接,然而,因?yàn)镕IFO具有名字,所以它可用于非線性連接。
考慮這樣一個(gè)操作過程,它需要對(duì)一個(gè)經(jīng)過過濾的輸入流進(jìn)行兩次處理。圖15-9表示了這種安排。
圖15-9 對(duì)一個(gè)經(jīng)過過濾的輸入流進(jìn)行兩次處理
使用FIFO以及UNIX系統(tǒng)程序tee(1),就可以實(shí)現(xiàn)這樣的過程而無需使用臨時(shí)文件。(tee程序?qū)⑵錁?biāo)準(zhǔn)輸入同時(shí)復(fù)制到其標(biāo)準(zhǔn)輸出以及其命令行中包含的命名文件中。)
mkfifo fifo1 prog3 < fifo1 & prog1 < infile | tee fifo1 | prog2
我們創(chuàng)建FIFO,然后在后臺(tái)啟動(dòng)prog3,它從FIFO讀數(shù)據(jù)。然后啟動(dòng)prog1,用tee將其輸出發(fā)送到FIFO和prog2。圖15-10顯示了這種安排。
圖15-10 使用FIFO和tee將一個(gè)流發(fā)送到兩個(gè)進(jìn)程
實(shí)例:客戶進(jìn)程-服務(wù)器進(jìn)程使用FIFO進(jìn)行通信
FIFO的另一個(gè)應(yīng)用是在客戶進(jìn)程和服務(wù)器進(jìn)程之間傳送數(shù)據(jù)。如果有一個(gè)服務(wù)器進(jìn)程,它與很多客戶進(jìn)程有關(guān),則每個(gè)客戶進(jìn)程都可將其請(qǐng)求寫到一個(gè)該服務(wù)器進(jìn)程創(chuàng)建的眾所周知的FIFO中(“眾所周知”的意思是:所有需要與服務(wù)器進(jìn)程聯(lián)系的客戶進(jìn)程都知道該FIFO的路徑名)。圖15-11顯示了這種安排。因?yàn)閷?duì)于該FIFO有多個(gè)寫進(jìn)程,客戶進(jìn)程發(fā)送給服務(wù)器進(jìn)程的請(qǐng)求其長度要小于字節(jié)。這就能避免客戶多個(gè)write之間的交錯(cuò)()。
圖15-11 客戶進(jìn)程用FIFO向服務(wù)器進(jìn)程發(fā)送請(qǐng)求
在這種類型的客戶進(jìn)程-服務(wù)器進(jìn)程通信中使用FIFO的問題是:服務(wù)器進(jìn)程如何將回答送回各個(gè)客戶進(jìn)程。不能使用單個(gè)FIFO,因?yàn)榉?wù)器進(jìn)程會(huì)發(fā)出對(duì)各個(gè)客戶進(jìn)程請(qǐng)求的響應(yīng),而請(qǐng)求者卻不可能知道什么時(shí)候去讀才能恰如其分地讀到對(duì)它的響應(yīng)。一種解決方法是每個(gè)客戶進(jìn)程都在其請(qǐng)求中包含它的進(jìn)程ID。然后服務(wù)器進(jìn)程為每個(gè)客戶進(jìn)程創(chuàng)建一個(gè)FIFO,所使用的路徑名是以客戶進(jìn)程的進(jìn)程ID為基礎(chǔ)的。例如,服務(wù)器進(jìn)程可以用名字/tmp/serv1.XXXXX創(chuàng)建FIFO,其中XXXXX被替換成客戶進(jìn)程的進(jìn)程ID。圖15-12顯示了這種安排。
圖15-12 客戶進(jìn)程-服務(wù)器進(jìn)程用FIFO進(jìn)行通信
這種安排可以工作,但也有一些不足之處。其中之一是服務(wù)器進(jìn)程不能判斷一個(gè)客戶進(jìn)程是否崩潰終止對(duì)進(jìn)程之間信息的復(fù)制,這就使得客戶進(jìn)程專用的FIFO會(huì)遺留在文件系統(tǒng)中。另一個(gè)不足之處是服務(wù)器進(jìn)程必須捕捉信號(hào)對(duì)進(jìn)程之間信息的復(fù)制,因?yàn)榭蛻暨M(jìn)程在發(fā)送一個(gè)請(qǐng)求后沒有讀取響應(yīng)就可能終止,于是留下一個(gè)只有寫進(jìn)程(服務(wù)器進(jìn)程)而無讀進(jìn)程的客戶進(jìn)程專用FIFO。
按照?qǐng)D15-12中的安排,如果服務(wù)器進(jìn)程以只讀方式打開眾所周知的FIFO(因?yàn)樗恍枳x該FIFO),則每當(dāng)客戶進(jìn)程數(shù)從1變成0時(shí),服務(wù)器進(jìn)程就將在FIFO中讀到一個(gè)文件結(jié)束標(biāo)記。為使服務(wù)器進(jìn)程免于處理這種情況,一種常用的技巧是使服務(wù)器進(jìn)程以讀-寫方式打開其FIFO。
社區(qū)發(fā)起?晨讀計(jì)劃?,每天堅(jiān)持積累一點(diǎn),今天的努力至少讓我們比昨天更進(jìn)一步。
?晨讀計(jì)劃? 期待你的加入... ...
:基于的高性能Web應(yīng)用開發(fā)框架