Linux pipe 匿名管道 淺解

2022-08-30 01:45:09 字數 3724 閱讀 9125

管道

1 使用訊號進行通訊

程序之間使用「訊號」進行通訊的優缺點

優點:簡單

缺點:傳遞的資訊有限,

只能傳遞乙個簡單的「訊號值」

解決方案:

使用「管道」進行程序間通訊。

注: 程序間通訊,簡稱「ipc」

2 什麼是管道

ipc 有多種方式, 管道是ipc的最基本的方式.

管道是「半雙工」的,即是單向的。

管道是fifo(先進先出)的。

單程序中的管道:

int fd[2]

使用檔案描述符fd[1], 向管道寫資料

使用檔案描述符fd[0], 從管道讀資料

fd[0]

使用者程序

fd[1]

使用者程序

fd[1]

fd[0] 讀 寫

管道

核心

注:單程序中的管道無實際用處

管道用於多程序間通訊。

3 管道的建立

使用pipe系統呼叫

用法:見 man 2 pipe

返回值:

成功:返回 0

失敗:返回 -1

注意:獲取兩個「檔案描述符」

分別對應管道的讀端和寫端。

fd[0]: 是管道的讀端

fd[1]: 是管道的寫端

如果對fd[0]進行寫操作,對fd[1]進行讀操作,可能導致不可預期的錯誤。

4 管道的使用

例項1:單程序使用管道進行通訊

main1. c

注意:建立管道後,獲得該管道的兩個檔案描述符,

不需要普通檔案操作中的open操作

如圖:例項2:多程序使用管道進行通訊

main2.c

注意:建立管道之後,再建立子程序,此時一共有4個檔案描述符。

4個埠,父子程序分別有乙個讀埠和乙個寫埠

向任意乙個寫埠寫資料,即可從任意乙個讀埠獲取資料。

如圖:例項3:子程序使用exec啟動新程式時管道的使用

main3.c

有程式p1, p2

使用管道進行通訊

p1由使用者輸入乙個字串,然後把該字串發給p2

p2接收到以後,把該字串列印出來

p1:

建立管道

建立子程序

在子程序中用exec替換成p2,

(在使用exec 時,把管道的讀端作為exec的引數)

在父程序中,獲取使用者的輸入,然後把所輸入的字串傳送給p2

(即,父程序把字串寫入管道)

p2:

從引數中獲取管道的讀端(引數即為p2的main函式的引數)

讀管道

把讀到的字串列印出來

難點:子程序使用exec啟動新程式執行後,

新程序能夠使用原來子程序的管道(因為exec能共享原來的檔案描述符)

但問題是新程序並不知道原來的檔案描述符是多少!

解決方案:

把子程序中的管道檔案描述符,用exec的引數傳遞給新程序。

例項4:關閉管道的讀端/寫端

管道關閉後的讀操作:

問題:

對管道進行read時,如果管道中已經沒有資料了,此時讀操作將被「阻塞」。

如果此時管道的寫端已經被close了,則寫操作將可能被一直阻塞!

而此時的阻塞已經沒有任何意義了。(因為管道的寫端已經被關閉,即不會再寫入資料了)

解決方案:

如果不準備再向管道寫入資料,則把該管道的所有寫端都關閉,

則,此時再對該管道read時,就會返回0,而不再阻塞該讀操作。(管道的特性)

注意,這是管道的特性。

如果有多個寫埠,而只關閉了乙個寫端,那麼無資料時讀操作仍將被阻塞。

實際實現方式:

父子程序各有乙個管道的讀端和寫端;

把父程序的讀端(或寫端)關閉;

把子程序的寫端(或讀端)關閉;

使這個「4埠」管道變成單向的「2埠」管道,如圖:

**:main4.c

(改寫main2.c)

把父程序的寫操作注釋掉,此時子程序的讀操作將被一直阻塞

把父程序的寫操作注釋掉,並close父程序的寫端

此時子程序的讀操作將將被阻塞。

把父程序的寫操作注釋掉,並把父子程序的寫端都close

此時子程序讀操作將直接返回0,而不再阻塞。

最終實現方案:

關閉父程序的讀端,關閉子程序的寫端。

當父程序不再傳送資料時,就關閉本程序的寫端。

練習:建立乙個子程序

父程序通過管道向子程序傳送資料(字串)

該字串由使用者輸入。

當使用者輸入」exit」時, 就不再向子程序傳送資料,並關閉該端的管道。

子程序從管道讀取資料,並輸出。

直到父程序關閉了管道的寫端。

練習:main5.c

建立乙個子程序

父程序:

迴圈等待使用者輸入,

使用者每輸入乙個單詞後,就把該單詞用管道傳送給子程序,

直到使用者輸入exit。

子程序:

每收到乙個單詞後,就列印輸出

直到使用者在父程序中結束輸入。

例項5 把管道作為標準輸入和標準輸出

把管道作為標準輸入和標準輸出的優點:

子程序使用exec啟動新程式時,就不需要再把管道的檔案描述符傳遞給新程式了。

可以直接使用使用標準輸入(或標準輸出)的程式。

比如 od –c (統計字元個數,結果為八進位制)

實現原理:

使用dup複製檔案描述符

用exec啟動新程式後,原程序中已開啟的檔案描述符仍保持開啟,

即可以共享原程序中的檔案描述符。

**:main6.c (修改main3.c)

注意:dup的用法

dup複製檔案描述符,

返回的新檔案描述符和被複製的檔案描述符,指向同乙個檔案或管道

5 使用popen/pclose

popen的作用:

用來在兩個程式之間傳遞資料:

在程式a中使用popen呼叫程式b時,有兩種用法:

程式a讀取程式b的輸出(使用fread讀取)

程式a傳送資料給程式b,以作為程式b的標準輸入。(使用fwrite寫入)

用法:man popen

返回值:成功,返回file*

失敗, 返回空

例項1: 讀取外部程式的輸出

main7.c

例項2:把輸出寫到外部程式

main8.c

popen的原理:

先使用fork建立乙個子程序,

然後在子程序中使用exec執行指定外部程式,並返回乙個檔案指標file*給父程序。

當使用」r」時,該file指向外部程式的標準輸出

當使用」w」時,該file指向外部程式的標準輸入。

popen的優缺點:

優點:可以使用shell擴充套件(比如命令中可以使用萬用字元)

使用方便。

缺點:每呼叫一次popen, 將要啟動兩個程序(shell和被指定的程式),

資源消耗大。

如果所有管道寫端對應的檔案描述符被關閉,則read返回0

如果所有管道讀端對應的檔案描述符被關閉,則write操作會產生訊號sigpipe

命名管道 匿名管道

有名字 則可以通過 名字 開啟相同的管道進行通訊,沒有名字 在核心中沒有明確標識 只能通過 子程序複製父程序的方式實現通訊,複製了檔案描述符 匿名管道只能用於具有親緣關係的程序間通訊。只要在建立程序之前建立管道,後邊的程序都可以實現通訊。命名管道可用於同一主機任意程序間通訊 作業系統在核心提供的一塊...

命名管道和匿名管道

我們知道程序間是可以通訊的。可以達到資料傳輸 資源共享 事件通知 程序控制等目的。程序間通訊主要包括管道 系統ipc,套接字等。管道分為三種 1 普通管道 int pipe int fds 2 返回值0表示成功,1表示失敗 fd 0 讀 fd 1 寫 子程序往管道中寫資料,寫資料時要關閉讀端 父程序...

語言 管道 建立匿名管道

本質 特點 實現方式 侷限性 匿名管道 僅適用於有血緣關係的程序通訊.本功能實現的是 ps axu grep bash 通過呼叫 ps 和 grep命令 然後分別將他們的輸出 和 輸入的檔案描述符改變.從終端改入到管道中.intmain int argc,char ar pid t pid fork...