IPC : (1) pipe & fifo
PIPE & FIFO 簡介
Pipe 與 fifo 為 Linux IPC(Inter-process communication)的方式之一.
共同的部分為
(1) 建立一個單向的 data channel.
(2) 同樣使用 fd(file descriptor) 作為讀寫的媒介.
(3) 預設讀取端(read)沒資料讀取會被鎖住(block), 直到寫入端(write)寫入資料. 相反過來 pipe buffer 滿了, write 會被鎖住(block). 若想改為非鎖住(non-block)則可透過 fcntl 或於 API 設置相關 flag 參數(如果 API 提供)
存取限制的部分
(1) pipe 僅舉限於關聯的 processes.
(2) fifo 則是透過 permission mask 來作為限制.
相關的特性如下表所示[1].
類型 | 識別名稱 | 於系統的表示 | 存取特性 | persistence |
---|---|---|---|---|
pipe | no name | fd | Only by related processes | process |
FIFO | path name | fd | permission mask | process (?) |
API 範例
以下針對兩個 API 個別進行說明. 其個別完整的範例程式可於 github 看到Pipe[2]
API 說明
#include <unistd.h> int pipe(int pipefd[2]); #define _GNU_SOURCE /* See feature_test_macros(7) */ #include <fcntl.h> /* Obtain O_* constant definitions */ #include <unistd.h> int pipe2(int pipefd[2], int flags);
pipe 與 pipe2 API 會建立一個單向的 data channel.
pipefd[0] 作為 pipe 的讀取端(read),
pipefd[1] 作為 piep 的寫入端(write).
pipe2 API 額外新增一個 flag 參數. 可參考下方說明[2]
O_NONBLOCK Set the O_NONBLOCK file status flag on the two new open file descriptions. Using this flag saves extra calls to fcntl(2) to achieve the same result. O_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the two new file descriptors. See the description of the same flag in open(2) for reasons why this may be useful.
API 範例
int pipefd[2] = {0}; char buf; // create pipe if (-1 == pipe(pipefd)) { ... } switch(fork()) { // Child reads from pipe case 0: close(pipefd[1]); read(pipefd[0], &buf, 1); close(pipefd[0]); .... // parent write data to pipe default: close(pipefd[0]); write(pipefd[1], SZ_HELLO, strlen(SZ_HELLO)); close(pipefd[1]); .... }
帶入一個 int array 至 pipe API, 藉此產生一個 pipe channel. 再透過 fork 複製一個 process 出來. 由 child 負責讀取(pipefd[0]). parent 負責寫入(pipefd[1]).
FIFO[3]
API 說明
#include <sys/types.h>#include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);
mkdifo API 類似 pipe(pipe2) 都是產生單方向的 data channel. 不同點是
(1) 藉由 pathname 建立一個可識別的特殊 fifo 檔案. 知道此 pathname 的 process 使用 open(const char *path, int oflag, ...) 打開此 fifo 檔案, 對檔案進行讀取或寫入.
(2) mode 參數設置此 fifo 檔案的權限為何, 限制其餘 process 的存取限制.
API 範例
#define SZ_FIFO_PATH "/tmp/fifo-example" switch(fork()) { // child => read data case 0: // wait a comment for creating fifo sleep(1); // open int fdFifo = 0; if(-1 == (fdFifo = open(SZ_FIFO_PATH, O_RDONLY))) { ... } // reading char buf; while(read(fdFifo, &buf, 1) > 0) write(STDOUT_FILENO, &buf, 1); write(STDOUT_FILENO, "\n", 1); .... break; // parent => craete fifo and write data default: // create fifo with name if(-1 == mkfifo(SZ_FIFO_PATH, S_IRWXU)) { ... } // open fifo int fdFifo = 0; if(-1 == (fdFifo = open(SZ_FIFO_PATH, O_WRONLY))) { ... } // writing write(fdFifo, "hello", strlen("hello")); ... break; }
先 fork child process 出來. parent 負責建立 fifo, 並寫入資料到 fifo 檔案. child 則是等待一會. 接著打開 fifo 檔案, 並開始讀取資料.
留言
張貼留言