1. 程式人生 > >【Linux/OS/Network】匿名管道(pipe)和命名管道(FIFO)

【Linux/OS/Network】匿名管道(pipe)和命名管道(FIFO)

匿名管道(pipe)

管道是一種最基本的IPC機制,由pipe函式建立:

“#include < unistd.h >”

函式原型:int pipe(int filedes[2]);

呼叫pipe函式時在核心中開闢一塊緩衝區(稱為管道)用於通訊,它有一個讀端一個寫端,然後通過filedes引數傳出給使用者程式兩個檔案描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記,就像0是標準輸入1是標準輸出一樣)。所以管道在使用者程式看起來就像一個開啟的檔案,通過read(filedes[0]);或者write(filedes[1]);向這個檔案讀寫資料其實是在讀寫核心緩衝區。pipe函式呼叫成功返回0,呼叫失敗返回-1。

開闢了管道之後如何實現兩個程序間的通訊?如下:

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

1. 父程序呼叫pipe開闢管道,得到兩個檔案描述符指向管道的兩端。

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

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

  • 使用管道有一些限制:
    1、兩個程序通過一個管道只能實現單向通訊。
    2、管道的讀寫端通過開啟的檔案描述符來傳遞,因此要通訊的兩個程序必須從它們的公共祖先那裡繼承管道檔案描述符。

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

    1、如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引用計數等於0),而仍然有程序 從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像讀到檔案末尾一樣。
    2、如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數大於0),而持有管道寫端的 程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。
    3、如果所有指向管道讀端的檔案描述符都關閉了(管道讀端的引用計數等於0),這時有程序向管道的寫端write,那麼該程序會收到訊號SIGPIPE,通常會導致程序異常終止。
    4、

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

命名管道(FIFO)

命名管道相關程式碼見:

一 .概念

管道的一個不足之處是沒有名字,因此,只能用於具有親緣關係的程序間通訊,在命名管道(named pipe或FIFO)提出後,該限制得到了克服。FIFO不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的檔案形式儲存於檔案系統中。命名管道是一個裝置檔案,因此,即使程序與建立FIFO的程序不存在親緣關係,只要可以訪問該路徑,就能夠通過FIFO相互通訊。值得注意的是,FIFO(first input first output)總是按照先進先出的原則工作,第一個被寫入的資料將首先從管道中讀出。

二、命名管道的建立與讀寫

Linux下有兩種方式建立命名管道。
一、在Shell下互動地建立一個命名管道。
二、在程式中使用系統函式建立命名管道。Shell方式下可使用mknod或mkfifo命令。建立命名管道的系統函式有兩個:mknod和mkfifo。函式原型如下:
“#include < sys/types.h >”
“#include < sys/stat.h >”
int mknod(const char *path,mode_t mod,dev_t dev);
int mkfifo(const char *path,mode_t mode);
函式mknod引數中path為建立的命名管道的全路徑名:mod為建立的命名管道的模式,指明其存取許可權;dev為裝置值,該值取決於檔案建立的種類,它只在建立裝置檔案時才會用到。這兩個函式呼叫成功都返回0,失敗都返回-1。

命名管道建立後就可以使用了,命名管道和管道的使用方法基本是相同的。只是使用命名管道時,必須先呼叫open()將其開啟。因為命名管道是一個存在於硬碟上的檔案,而管道是存在於記憶體中的特殊檔案。需要注意的是,呼叫open()開啟命名管道的程序可能會被阻塞。但如果同時用讀寫方式(O_RDWR)開啟,則一定不會導致阻塞;如果以只讀方式(O_RDONLY)開啟,則呼叫open()函式的程序將會被阻塞直到有寫方開啟管道;同樣以寫方式(O_WRONLY)開啟也會阻塞直到有讀方式開啟管道。

總結:pipe與FIFO間的區別

1、對檔案系統來說,匿名管道是不可見的,它的作用僅限於在父程序和子程序兩個程序間進行通訊。而命名管道是一個可見的檔案

2、pipe只能是兩個具有公共祖先的程序間進行通訊,而FIFO可以用於任何兩個程序之間的通訊,不管這兩個程序是不是父子程序,也不管這兩個程序之間有沒有關係。

3、pipe創建出來的管道沒有名字,而FIFO是通過唯一路徑來標識唯一的命名管道。