Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> 關於 Linux

Linux FIFO 命名管道建立與應用完整指南

編輯:關於 Linux

FIFO(First In, First Out),又稱命名管道,是 Linux 進程間通訊(IPC)機制之一。與無名管道(pipe(),僅限親緣關係進程)不同,FIFO 在檔案系統中擁有路徑與 inode,任何知曉路徑的進程皆可開啟讀寫,極大擴展了適用場景。本文涵蓋建立方法(指令與系統呼叫)、核心特性、讀寫規則與典型應用模式。

FIFO vs 無名管道 比較

特性FIFO (命名管道)Pipe (無名管道)
檔案系統實體有(ls -l 顯示 p 型態)無(僅存在核心記憶體)
存取方式路徑名稱(open()、fopen())檔案描述符傳遞(fork() 繼承)
適用進程任意無關進程親緣進程(父子、兄弟)
生命週期檔案刪除前持續存在進程結束自動銷毀
建立指令mkfifo, mknodShell |, pipe() 系統呼叫

指令列建立與操作

1. mkfifo 指令

mkfifo /tmp/my_fifo
# 或指定權限
mkfifo -m 600 /tmp/my_fifo

驗證:

ls -l /tmp/my_fifo
# prw-r--r-- 1 user user 0 Mar 15 10:30 /tmp/my_fifo|

p 表示 FIFO 型態,大小永遠為 0(資料在核心緩衝區流動)。

2. Shell 實測:生產者/消費者

終端機 1(寫入端):

echo "Hello FIFO" > /tmp/my_fifo
# 此處阻塞,直到有讀取端開啟

終端機 2(讀取端):

cat /tmp/my_fifo
# 輸出: Hello FIFO
# 寫入端隨即解除阻塞結束

3. 非阻塞開啟技巧

# 讀取端非阻塞(立即返回,無資料則 EOF)
cat /tmp/my_fifo &
# 寫入端
echo "test" > /tmp/my_fifo

C 語言系統呼叫建立

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

int main() {
    const char *path = "/tmp/my_fifo";
    
    // 1. 設定 umask 確保權限
    mode_t old_mask = umask(0);
    
    // 2. 移除舊檔案(避免 EEXIST)
    unlink(path);
    
    // 3. 建立 FIFO (mkfifo 相當於 mknod(path, S_IFIFO|mode, 0))
    if (mkfifo(path, 0600) == -1) {
        perror("mkfifo");
        return 1;
    }
    umask(old_mask);
    
    // 4. 開啟讀寫(注意:預設阻塞直到對端開啟)
    int fd_write = open(path, O_WRONLY);  // 阻塞直到有讀者
    int fd_read  = open(path, O_RDONLY);  // 阻塞直到有寫者
    
    // 5. 讀寫操作同一般檔案
    write(fd_write, "data", 4);
    char buf[128];
    read(fd_read, buf, sizeof(buf));
    
    close(fd_write);
    close(fd_read);
    unlink(path);  // 清理
    return 0;
}

核心特性與限制

  • PIPE_BUF 原子性:單次 write() ≤ PIPE_BUF(Linux 為 4096 bytes)保證原子寫入,不會與其他寫入者資料交錯。超過此大小可能分段。
  • 阻塞語意:
    • 唯讀 open():阻塞直到有寫入者開啟。
    • 唯寫 open():阻塞直到有讀取者開啟。
    • 非阻塞模式(O_NONBLOCK):唯讀立即成功;唯寫若無讀者立即失敗返回 ENXIO。
  • EOF 判斷:當所有寫入端關閉,讀取端 read() 返回 0(EOF)。若仍有寫入端開啟,read() 阻塞等待資料。
  • 訊號處理:無讀者時寫入會收到 SIGPIPE(預設終止進程),建議 signal(SIGPIPE, SIG_IGN) 搭配檢查 write() 返回 EPIPE。

典型應用架構

1. 簡單生產者/消費者

# 生產者腳本 (producer.sh)
while true; do
    echo "$(date): sensor data" > /tmp/sensor_fifo
    sleep 1
done

# 消費者腳本 (consumer.sh)
while read line; do
    logger -t sensor "$line"
done < /tmp/sensor_fifo

2. Client/Server 架構

  • Server 建立知名 FIFO(/var/run/myserver/cmd_fifo),持續 read() 等待指令。
  • Client open(O_WRONLY) 寫入指令(含回覆用的私有 FIFO 路徑)。
  • Server 處理後寫入 Client 的私有 FIFO 回覆結果。

3. 日誌/資料流分流

# 主程式寫入單一 FIFO
exec 3> /tmp/log_fifo
echo "log entry" >&3

# 多個消費者分別處理
tee /tmp/log_fifo | grep ERROR | logger -t error &
tee /tmp/log_fifo | grep WARN  | logger -t warn  &
tee /tmp/log_fifo | cat > /var/log/full.log &

清理與最佳實踐

  • 程式結束前 unlink() 移除 FIFO 檔案,避免殘留。
  • 使用 O_CLOEXEC 旗標防止 exec() 時檔案描述符洩漏。
  • 高併發場景考慮 socketpair() 或 Unix Domain Socket(支援雙向、傳遞檔案描述符、SCM_RIGHTS)。
  • 監控 FIFO 狀態:lsof /tmp/my_fifo 查看開啟進程。

總結

FIFO 以「有名稱、檔案系統可見、任意進程可存取」特性,彌補了無名管道侷限於親緣進程的缺口。掌握 mkfifo、阻塞語意、PIPE_BUF 原子性與 EOF 條件,即可靈活構建輕量級 IPC 通道。對於雙向通訊、高併發、需傳遞檔案描述符的場景,建議升級至 Unix Domain Socket。

Copyright © Windows教程網 All Rights Reserved