各位讀者大家好,上一篇我們介紹了管道進行進程間通信的基本概念,本篇將深入講解第一種管道——偽管道的具體使用方法。讓我們繼續探索C語言進程通信的奧秘!
所謂「偽管道」,是指通過 popen 和 pclose 這兩個標準庫函數來創建和管理管道。它之所以被稱為「偽管道」,是因為 popen 的參數是一個 Linux 終端命令字符串,它通過啟動 Shell 來執行該命令,本質上與終端中使用「|」管道符的效果相同,但性能相對較低。
FILE *popen(const char *command, const char *open_mode);
"r"(讀)或 "w"(寫)。FILE*),可像操作普通文件一樣使用 fread/fwrite 等函數進行數據讀寫。通過傳入 env、grep 等 Linux 命令,popen 會啟動相應的子進程,主進程即可通過返回的文件流與子進程進行數據交換。
int pclose(FILE *stream);
popen 返回的文件流指針。該函數用於關閉 popen 打開的管道,釋放資源,通常在進程結束前調用。
popen 打開管道,指定讀/寫模式。fread/fwrite 進行數據讀寫。pclose 關閉管道。#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buffer[BUFSIZ + 1];
int read_count = 0;
FILE *p_read, *p_write;
memset(buffer, '\0', sizeof(buffer));
// 以讀模式打開管道,執行 env 命令獲取環境變量
p_read = popen("env", "r");
if (NULL == p_read) {
printf("open pipe for reading failed\n");
return 1;
}
// 以寫模式打開管道,執行 grep bash 過濾包含 bash 的行
p_write = popen("grep bash", "w");
if (NULL == p_write) {
printf("open pipe for writing failed\n");
return 1;
}
// 從 env 進程讀取數據,寫入 grep 進程
read_count = fread(buffer, sizeof(char), BUFSIZ, p_read);
while (read_count > 0) {
fwrite(buffer, sizeof(char), strlen(buffer), p_write);
read_count = fread(buffer, sizeof(char), BUFSIZ, p_read);
}
pclose(p_read);
pclose(p_write);
return 0;
}
為了釐清讀寫模式的看似矛盾之處,我們假設三個進程:
env 命令啟動的子進程grep bash 命令啟動的子進程env 的執行結果)。grep 過濾後輸出結果。這樣就實現了:env 產生數據 → 主進程中轉 → grep 處理數據 → 最終輸出,完成進程間通信。
$ ./pipe_demo
SHELL=/bin/bash
對比終端直接執行管道命令:
$ env | grep bash
SHELL=/bin/bash
兩者結果完全一致,驗證了偽管道的效果等同於 Shell 管道操作。
完整代碼已上傳至資源庫,歡迎下載實踐。下一篇我們將介紹「入門級管道」——使用 pipe 系統調用配合 fork 實現父子進程通信,敬請期待!