從 0 開始學習 Linux 系列之「20.有名管道 FIFO」

FIFO

版權聲明:本文為 cdeveloper 原創文章,可以隨意轉載,但必須在明確位置注明出處!

FIFO 和 Pipe 的區別

上一篇文章我們了解了無名管道 Pipe 的原理,這篇文章我們來學習 IPC 的第二種方式 FIFO 有名管道,既然同為管道,它們兩個有什么區別呢?

  1. 相同點:Pipe 和 FIFO 都用管道來進行 IPC
  2. 相同點:Pipe 和 FIFO 的管道數據都存在內核內存的緩沖區中
  3. 不同點:Pipe 不在磁盤上建立管道文件,FIFO 在磁盤上建立管道文件
  4. 不同點:Pipe 需要通信的進程具有親緣關系,而 FIFO 在不相關的進程之間也能交換數據

有名管道 FIFO 和無名管道 Pipe 主要的區別就是 FIFO 在磁盤上建立管道文件(FIFO 將內核數據緩沖區映射到了實際的文件節點),所以我們可以在磁盤上實際看到,故稱為「有名字」,而 Pipe 沒有在磁盤上建立文件,我們不能實際看到,故稱為「無名」,其實就這么簡單的理解。了解了基本的區別,我們來看看操作 FIFO 的函數。

如何使用 FIFO?

我們使用 FIFO 是在磁盤上建立一個管道文件,然后利用這個文件作為管道的傳輸通道,但是這個管道文件很特殊,它的大小始終為 0,原因是管道的數據是存放在內核的內存中的,不在管道文件中,我們也可以驗證這個事實。

mkfifo 命令

shell 終端中你可以使用下面的命令來手動建立一個管道文件:

mkfifo fifo_file

然后看一些這個文件的屬性和大小,發現是黃色的管道文件( p ),大小始終為 0,并且你也不能手動使用編輯器來編輯這個文件:

ll fifo_file
# 結果
prw-r--r-- 1 orange orange 0 Aug  5 14:05 fifo_file|

vim fifo_file
# 不能編輯這個文件

來看個實際的例子。

mkfifo 函數

Linux 不僅提供了創建管道文件的命令,也提供了 API:

#include <sys/types.h>
#include <sys/stat.h>

/*
 * pathname:FIFO 文件名稱
 * mode:FIFO 文件訪問權限
 * return:成功返回 0, 失敗返回 -1, 并設置 erron
 */
int mkfifo(const char *pathname, mode_t mode);

例子:fifo_r.c,fifo_w.c

來看一個實際使用有名管道的例子,在這個例子中 fifo_w 向管道文件寫入數據,fifo_r 從管道中讀取數據。先看看寫入文件:

// fifo_w.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>

// FIFO 文件名
#define FIFO_PATH "fifo_file"


int main() { 
    // 創建 FIFO 文件,如果存在就不再創建
    if (mkfifo(FIFO_PATH, 0666) < 0 && errno != EEXIST) {
        perror("create fifo failed");
        return -1;
    } else { 
        char cont_w[] = "I'm FIFO write.\n";
        // 以只寫的方式打開
        int fd = open(FIFO_PATH, O_CREAT|O_WRONLY, 0666);
        if (fd > 0) {
            while (1) {
                // 循環寫入內容
                write(fd, cont_w, strlen(cont_w));
                sleep(1);
                printf("write: %s\n", cont_w);
            }
            close(fd);
        } 
    }

    return 0;
}

這是從 FIFO 文件中讀取:

// fifo_r.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>

// FIFO 文件名
#define FIFO_PATH "fifo_file"

int main() {
    // 創建 FIFO 文件,如果存在就不再創建
    if (mkfifo(FIFO_PATH, 0666) < 0 && errno != EEXIST) {
        perror("create fifo failed");
        return -1;
    } else { 
        char cont_r[255];
        // 以只讀的方式打開
        int fd = open(FIFO_PATH, O_CREAT | O_RDONLY, 0666);
        if (fd > 0) {
            while (1) {
                // 讀取 FIFO 中的內容
                read(fd, cont_r, 255);
                printf("read: %s\n", cont_r);
            }
            close(fd);
        }
    }

    return 0;
}

編譯運行

先編譯:

gcc fifo_w.c -o fifo_w
gcc fifo_r.c -o fifo_r

運行 fifo_w 寫入內容:

./fifo_w

再運行另一個 fifo_r 從管道中讀取內容:

./fifo_r

如果運行成功,會發現可以成功讀取寫入的內容,這跟 Pipe 的操作其實是相同的。但是要注意的是當運行 fifo_w,而沒有運行 fifo_r 的時候,寫入端將會阻塞,這主要是當用 open 打開 FIFO 文件時會有下面 2 個狀態:

  1. 在一般情況下(沒有指定 O_NONBLOCK),以只讀的方式 open FIFO 文件會阻塞到某個進程為寫而打開這個 FIFO 為止,同樣以只寫的方式 open FIFO 文件會阻塞到某個進程為讀而打開這個文件為止。
  2. 如果指定了 O_NONBLOCK,則只讀 open 立即返回,如果沒有進程為讀而打開一個 FIFO,那么只寫 open 將返回 -1,并將 erron 設置成 ENXIO。

下面也來分析下內核中的 FIFO 實現。

FIFO 的內核實現

FIFO 的內核實現和 Pipe 的大同小異,這里還是以 Linux-3.4 內核來分析,來看看 FIFO 在內核大體的執行過程:fs/fifo.c

fifo

fifo.c 實際上也是一個內核的驅動文件,從 fifo_open 開始,然后對文件進行加鎖,之后就像 Pipe 一樣為管道的內存數據分配內核內存空間,因為 FIFO 文件里面是不存儲數據的,數據都存儲在內核緩存區中,之后判斷當前的讀寫模式進行相應的操作,最后解鎖文件。

結語

這樣我們就學習了第二種 Linux IPC 機制:有名管道 FIFO。我們知道了 FIFO 和 Pipe 的機制是差不多的,只是 FIFO 在磁盤上有個可以看到的文件,實際的讀寫數據還是在內核內存中的。

Pipe 進行 IPC 需要進程有親緣關系,但是通過 FIFO,不相關的進程也能交換數據。shell 命令也是使用 FIFO 將數據從一條管道傳送到另一條,從而實現了命令的組合使用,并且無需創建中間臨時文件,例如:ps -aux | grep xxx。就這些了,希望你能認真實踐。

感謝你的閱讀,我們下次再見 :)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容