1. 程式人生 > >Linux 程序通訊之:命名管道 (FIFO)

Linux 程序通訊之:命名管道 (FIFO)

一、簡介

由於管道(Pipe)只能應用於存在血緣關係的程序間通訊,為了突破這個限制,使用命名管道(FIFO)來實現 不相干程序間 的通訊。

FIFO 是 Linux 基礎檔案型別中的一種,它並不佔用磁碟上實際的資料塊,而僅僅是標識核心中的一條通道。各程序可以開啟這個檔案進行 read/write,實際上是在讀寫核心通道。

二、API 說明

1. 標頭檔案

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

2. 建立一個 FIFO 檔案

int mkfifo(const char *pathname, mode_t mode);

3. 引數說明

  • pathname : 指定建立的檔案路徑名
  • mode : 指定檔案的訪問許可權,實際為一個形如 “rwxrwxrwx” 的 int 值,分別表示 “所有者”“所在組”“其他組” 的使用者訪問許可權。r 為可讀,值為 1;w 為可寫,值為 2;x 為可執行,值為 4。通常使用八進位制數來表示許可權。例如 0775

4. 返回值說明

成功返回 0,失敗返回 -1,並設定相應的 errno

注意 :如果檔案已存在,也會返回 -1,建立失敗的錯誤原因是:檔案已存在。

三、命名管道的開啟規則

1. 說明

注意,mkfifo 方法只是建立了一個這樣的檔案,可供其它程序操作。而其它程序想要使用該檔案進行通訊,還是需要像檔案操作一樣,開啟

讀或寫關閉 檔案的。

2. 開啟規則

開啟 FIFO 檔案通常有四種方式,即:

open(const char *path, O_RDONLY); // 只讀的方式開啟(會堵塞)
open(const char *path, O_RDONLY | O_NONBLOCK); // 非堵塞的只讀方式開啟
open(const char *path, O_WRONLY); // 只寫的方式開啟(會堵塞)
open(const char *path, O_WRONLY | O_NONBLOCK); // 非堵塞的只寫方式開啟

3. 規則說明

O_RDONLYO_WRONLY 我們已經很熟悉了,但 O_NONBLOCK

是什麼意思呢?

O_NONBLOCK 表示非堵塞的方式,預設情況下,開啟 FIFO 是會堵塞程序的。例如我們的 A 程序使用只讀的方式開啟檔案時,此時它會被堵塞住,直到有一個 B 程序以只寫的方式打開了同一個 FIFO 檔案。同理,先以只寫的方式開啟,也會堵塞住,直到有一個程序以只讀的方法開啟同一個 FIFO 檔案。

可能會覺得有點暈,下面通過一個實際例子,並給出執行的 gif 圖,來理解堵塞的含義。

示例

1. 寫程序

將一個 Hello World 寫到 FIFO 檔案中去。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main() {
    char pathname[] = "my_fifo";
    char buf[] = "Hello World\n";
    mkfifo(pathname, 0775);
    int fd = open(pathname, O_WRONLY);
    if (fd == -1) {
        perror("open failed\n");
        exit(EXIT_FAILURE);
    }
    write(fd, &buf, strlen(buf));
    printf("write done\n");
    close(fd);
    return 0;
}

2. 讀程序

讀取 FIFO 檔案中的資訊,並輸出到標準輸出流中。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main() {
    char pathname[] = "my_fifo";
    char buf[127] = { 0 };
    mkfifo(pathname, 0775);
    int fd = open(pathname, O_RDONLY);
    if (fd == -1) {
        perror("open failed\n");
        exit(EXIT_FAILURE);
    }
    int n;
    while ((n = read(fd, buf, 10)) > 0) {
        write(STDOUT_FILENO, &buf, n);
    }
    close(fd);
    return 0;
}

3. 執行示例

先執行讀的程式,open 會堵塞住等待讀入,再執行寫的程式,兩個程序都成功執行完畢。

同理反過來,先執行寫的程式,也會一直堵塞等待。

在這裡插入圖片描述

這裡展示的是先執行 的程序,再執行 的程序,可以觀察到確實會有堵塞的情況。

反過來也是一樣的會有先堵塞 程序,直到 程序執行時結束。