linux管道pipe詳解

2021-10-23 22:41:12 字數 3183 閱讀 8633

管道是一種最基本的ipc機制,作用於有血緣關係的程序之間,完成資料傳遞。呼叫pipe系統函式即可建立乙個管道。有如下特質:

1. 其本質是乙個偽檔案(實為核心緩衝區)

2. 由兩個檔案描述符引用,乙個表示讀端,乙個表示寫端。

3. 規定資料從管道的寫端流入管道,從讀端流出。

管道的原理: 管道實為核心使用環形佇列機制,借助核心緩衝區(4k)實現。

管道的侷限性:

① 資料自己讀不能自己寫。

② 資料一旦被讀走,便不在管道中存在,不可反覆讀取。

③ 由於管道採用半雙工通訊方式。因此,資料只能在乙個方向上流動。

④ 只能在有公共祖先的程序間使用管道。

常見的通訊方式有,單工通訊、半雙工通訊、全雙工通訊。

建立管道

int pipe(int pipefd[2]); 成功:0;失敗:-1,設定errno

函式呼叫成功返回r/w兩個檔案描述符。無需open,但需手動close。規定:fd[0] → r; fd[1] → w,就像0對應標準輸入,1對應標準輸出一樣。向管道檔案讀寫資料其實是在讀寫核心緩衝區。

管道建立成功以後,建立該管道的程序(父程序)同時掌握著管道的讀端和寫端。如何實現父子程序間通訊呢?通常可以採用如下步驟:

1. 父程序呼叫pipe函式建立管道,得到兩個檔案描述符fd[0]、fd[1]指向管道的讀端和寫端。

2. 父程序呼叫fork建立子程序,那麼子程序也有兩個檔案描述符指向同一管道。

3. 父程序關閉管道讀端,子程序關閉管道寫端。父程序可以向管道中寫入資料,子程序將管道中的資料讀出。由於管道是利用環形佇列實現的,資料從寫端流入管道,從讀端流出,這樣就實現了程序間通訊。

練習:父子程序使用管道通訊,父寫入字串,子程序讀出並,列印到螢幕。 【pipe.c】

思考:為甚麼,程式中沒有使用sleep函式,但依然能保證子程序執行時一定會讀到資料呢?

#include #include #include #include #include void sys_err(const char *str)  

int main(void)

else if (pid == 0) else

return 0;

}

使用管道需要注意以下4種特殊情況(假設都是阻塞i/o操作,沒有設定o_nonblock標誌):

1. 如果所有指向管道寫端的檔案描述符都關閉了(管道寫端引用計數為0),而仍然有程序從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像讀到檔案末尾一樣。

2. 如果有指向管道寫端的檔案描述符沒關閉(管道寫端引用計數大於0),而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。

3. 如果所有指向管道讀端的檔案描述符都關閉了(管道讀端引用計數為0),這時有程序向管道的寫端write,那麼該程序會收到訊號sigpipe,通常會導致程序異常終止。當然也可以對sigpipe訊號實施捕捉,不終止程序。具體方法訊號章節詳細介紹。

4. 如果有指向管道讀端的檔案描述符沒關閉(管道讀端引用計數大於0),而持有管道讀端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入資料並返回。

總結:① 讀管道:

1. 管道中有資料,read返回實際讀到的位元組數。

2. 管道中無資料:

(1) 管道寫端被全部關閉,read返回0 (好像讀到檔案結尾)

(2) 寫端沒有全部被關閉,read阻塞等待(不久的將來可能有資料遞達,此時會讓出cpu)

② 寫管道:

1. 管道讀端全部被關閉, 程序異常終止(也可使用捕捉sigpipe訊號,使程序不終止)

2. 管道讀端沒有全部關閉:

(1) 管道已滿,write阻塞。

(2) 管道未滿,write將資料寫入,並返回實際寫入的位元組數。

練習:使用管道實現父子程序間通訊,完成:ls | wc –l。假定父程序實現ls,子程序實現wc。

ls命令正常會將結果集寫出到stdout,但現在會寫入管道的寫端;wc –l 正常應該從stdin讀取資料,但此時會從管道的讀端讀。      【pipe1.c】

#include #include #include int main(void)

else

return 0; }

/** 程式不時的會出現先列印$提示符,再出程式執行結果的現象。

* 這是因為:父程序執行ls命令,將輸出結果給通過管道傳遞給

* 子程序去執行wc命令,這時父程序若先於子程序列印wc執行結果

* 之前被shell使用wait函式成功**,shell就會先於子程序列印

* wc執行結果之前列印$提示符。

* 解決方法:讓子程序執行ls,父程序執行wc命令。或者在兄弟程序間完成。

*/

程式執行,發現程式執行結束,shell還在阻塞等待使用者輸入。這是因為,shell → fork → ./pipe1, 程式pipe1的子程序將stdin重定向給管道,父程序執行的ls會將結果集通過管道寫給子程序。若父程序在子程序列印wc的結果到螢幕之前被shell呼叫wait**,shell就會先輸出$提示符。

練習:使用管道實現兄弟程序間通訊。 兄:ls  弟: wc -l  父:等待**子程序。

要求,使用「迴圈建立n個子程序」模型建立兄弟程序,使用迴圈因子i標示。注意管道讀寫行為。 【pipe2.c】

#include #include #include int main(void)  

} if (i == 0) else if (i == 1) else

return 0;

}

測試:是否允許,乙個pipe有乙個寫端,多個讀端呢?是否允許有乙個讀端多個寫端呢? 【pipe3.c】

#include #include #include #include #include int main(void)  

for(i = 0; i < 2; i++) }

if (i == 0) else if(i == 1) else

return 0;

}

linux管道pipe詳解

管道是一種最基本的ipc機制,作用於有血緣關係的程序之間,完成資料傳遞。呼叫pipe系統函式即可建立乙個管道。有如下特質 1.其本質是乙個偽檔案 實為核心緩衝區 2.由兩個檔案描述符引用,乙個表示讀端,乙個表示寫端。3.規定資料從管道的寫端流入管道,從讀端流出。管道的原理 管道實為核心使用環形佇列機...

linux管道通訊(pipe)

linux pipe適合於父子程序之間進行通訊。如下面 所示 include include include int main create sub process pid fork if 1 pid else if 0 pid else return 0 當呼叫fork函式後,fork將會返回兩個...

linux 匿名管道pipe

管道是一種最基本的ipc機制,由pipe函式建立 include int pipe int filedes 2 呼叫pipe函式時在核心中開闢一塊緩衝區 稱為管道 用於通訊,它有乙個讀端乙個寫端,然後通 過filedes引數傳出給使用者程式兩個檔案描述符,filedes 0 指向管道的讀端,file...