WeHelp
C 語言可以直接呼叫作業系統提供的 System Call 且速度極快,用來開發基礎系統程式非常適合。
  1. C 系統程式
  2. C 檔案寫入、讀取
  3. Process 程序管理
  4. Thread 執行緒管理
  5. IPC 程序間通訊
  6. PIPE 程序間通訊
  7. FIFO 程序間通訊
  8. 共享記憶體通訊
  9. Socket 程序間通訊
  10. TCP 網路連線
FIFO 程序間通訊
## IPC FIFO 簡介 FIFO(Named Pipe,具名管道)是一種 IPC(Inter-Process Communication)機制,讓不同的程序透過檔案系統中的一個特殊檔案交換資料。 ### FIFO 的主要特性 - **具有名稱**:通常存在於檔案系統中,例如 `/tmp/myfifo`。 - **可供無親緣關係的程序使用**:不同於匿名 pipe,不要求程序之間具有父子關係。 - **單向、串流式通訊**:資料沒有訊息邊界,使用 `read()` 和 `write()` 讀寫位元組資料。 - **先進先出**:先寫入的資料會先被讀出。 - **核心提供緩衝區**:資料會暫存在核心的 FIFO buffer 中。 - **通常會阻塞**: - `open(path, O_WRONLY)` 通常會等待讀端開啟。 - `open(path, O_RDONLY)` 通常會等待寫端開啟。 - `read()` 沒有資料時可能阻塞。 - `write()` 緩衝區滿時可能阻塞。 - **不適合隨機存取**:不能使用 `lseek()`。 - **資料不會永久保存**:FIFO 檔案本身只是一個通訊端點,資料會被讀出或在程序結束後消失。 在 POSIX 系統中,若單次寫入資料不超過 `PIPE_BUF`,通常可保證該次寫入不會與其他程序的寫入交錯。 --- ## C 中使用 FIFO 的 System Call 常用的系統呼叫如下: | 函式 | 功能 | |---|---| | `mkfifo()` | 建立 FIFO 特殊檔案 | | `open()` | 開啟 FIFO,指定讀取或寫入模式 | | `read()` | 從 FIFO 讀取資料 | | `write()` | 寫入資料到 FIFO | | `close()` | 關閉 FIFO | | `unlink()` | 刪除 FIFO 檔案 | 嚴格來說,C 程式通常呼叫的是 libc 提供的函式包裝器,而這些函式會進一步執行對應的 Linux System Call。 --- ## 簡單範例 以下程式可當作讀端或寫端執行。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> // O_RDONLY, O_WRONLY #include <sys/stat.h> // mkfifo #include <unistd.h> // read, write, close #include <errno.h> #define FIFO_PATH "/tmp/example_fifo" int main(int argc, char *argv[]) { int fd; if (argc != 2) { fprintf(stderr, "用法:%s read|write\n", argv[0]); return 1; } /* * 建立 FIFO。 * 若 FIFO 已經存在,mkfifo() 會失敗,但不算錯誤。 */ if (mkfifo(FIFO_PATH, 0666) == -1 && errno != EEXIST) { perror("mkfifo"); return 1; } if (strcmp(argv[1], "write") == 0) { const char *msg = "Hello from FIFO writer!\n"; /* * 若目前沒有讀端,這裡通常會阻塞, * 直到另一個程序以 O_RDONLY 開啟 FIFO。 */ fd = open(FIFO_PATH, O_WRONLY); if (fd == -1) { perror("open for writing"); return 1; } if (write(fd, msg, strlen(msg)) == -1) { perror("write"); } close(fd); } else if (strcmp(argv[1], "read") == 0) { char buffer[128]; ssize_t n; /* * 若目前沒有寫端,這裡通常會阻塞, * 直到另一個程序以 O_WRONLY 開啟 FIFO。 */ fd = open(FIFO_PATH, O_RDONLY); if (fd == -1) { perror("open for reading"); return 1; } n = read(fd, buffer, sizeof(buffer) - 1); if (n == -1) { perror("read"); } else { buffer[n] = '\0'; printf("收到資料:%s", buffer); } close(fd); /* * 讀端結束後刪除 FIFO 名稱。 * 注意:若其他程序仍開啟 FIFO,該開啟的描述元仍可使用。 */ unlink(FIFO_PATH); } else { fprintf(stderr, "參數必須是 read 或 write\n"); return 1; } return 0; } ``` ### 編譯與執行 ```bash gcc fifo.c -o fifo ``` 先開啟讀端: ```bash ./fifo read ``` 再開啟另一個終端機執行寫端: ```bash ./fifo write ``` 讀端會顯示: ```text 收到資料:Hello from FIFO writer! ``` 這個例子中: 1. `mkfifo()` 建立 `/tmp/example_fifo`。 2. 讀端使用 `open(..., O_RDONLY)` 開啟。 3. 寫端使用 `open(..., O_WRONLY)` 開啟。 4. 寫端透過 `write()` 傳送資料。 5. 讀端透過 `read()` 接收資料。 6. 雙方使用 `close()` 關閉 FIFO,最後可用 `unlink()` 移除 FIFO 檔案。
相關學習地圖、教學課程
C 語言,系統程式
掌握基礎的 C 語法,以及進階的系統程式開發能力。