Linux 上實現雙向程序間通訊管道

2021-06-10 10:29:51 字數 2618 閱讀 3131

簡介:本文闡述了乙個使用 socketpair 系統呼叫在 linux 上實現雙向程序通訊管道的方法,並提供了乙個實現。

問題和常見方法

linux 提供了 popen 和 pclose 函式 (1),用於建立和關閉管道與另外乙個程序進行通訊。其介面如下:

file *popen(const char *command, const char *mode);

int pclose(file *stream);

遺憾的是,popen 建立的管道只能是單向的 -- mode 只能是 "r" 或 "w" 而不能是某種組合--使用者只能選擇要麼往裡寫,要麼從中讀,而不能同時在乙個管道中進行讀寫。實際應用中,經常會有同時進行讀寫的要求,比如,我們可能希望把文字資料送往sort工具排序後再取回結果。此時popen就無法用上了。我們需要尋找其它的解決方案。

有一種解決方案是使用 pipe 函式 (2)建立兩個單向管道。沒有錯誤檢測的**示意如下:

int pipe_in[2], pipe_out[2];

pid_t pid;

pipe(&pipe_in); // 建立父程序中用於讀取資料的管道

pipe(&pipe_out); // 建立父程序中用於寫入資料的管道

if ( (pid = fork()) == 0) else

當然,這樣的**的可讀性(特別是加上錯誤處理**之後)比較差,也不容易封裝成類似於popen/pclose的函式,方便高層**使用。究其原因,是pipe函式返回的一對檔案描述符只能從第乙個中讀、第二個中寫(至少對於linux是如此)。為了同時讀寫,就只能採取這麼累贅的兩個pipe呼叫、兩個檔案描述符的形式了。

回頁首

乙個更好的方案

使用pipe就只能如此了。不過,linux實現了乙個源自bsd的socketpair呼叫 (3),可以實現上述在同乙個檔案描述符中進行讀寫的功能(該呼叫目前也是posix規範的一部分 (4))。該系統呼叫能建立一對已連線的(unix族)無名socket。在linux中,完全可以把這一對socket當成pipe返回的檔案描述符一樣使用,唯一的區別就是這一對檔案描述符中的任何乙個都可讀和可寫。

這似乎可以是乙個用來實現程序間通訊管道的好方法。不過,要注意的是,為了解決我前面的提出的使用sort的應用問題,我們需要關閉子程序的標準輸入通知子程序資料已經傳送完畢,而後從子程序的標準輸出中讀取資料直到遇到eof。使用兩個單向管道的話每個管道可以單獨關閉,因而不存在任何問題;而在使用雙向管道時,如果不關閉管道就無法通知對端資料已經傳送完畢,但關閉了管道又無法從中讀取結果資料。——這一問題不解決的話,使用socketpair的設想就變得毫無意義。

令人高興的是,shutdown呼叫 (5)可解決此問題。畢竟socketpair產生的檔案描述符是一對socket,socket上的標準操作都可以使用,其中也包括shutdown。——利用shutdown,可以實現乙個半關閉操作,通知對端本程序不再傳送資料,同時仍可以利用該檔案描述符接收來自對端的資料。沒有錯誤檢測的**示意如下:

int fd[2];

pid_t pid;

socketpair(af_unix, socket_stream, 0, fd); // 建立管道

if ( (pid = fork()) == 0) else

很清楚,這比使用兩個單向管道的方案要簡潔不少。我將在此基礎上作進一步的封裝和改進。

回頁首

封裝和實現

直接使用上面的方法,無論怎麼看,至少也是醜陋和不方便的。程式的維護者想看到的是程式的邏輯,而不是完成一件任務的各種各樣的繁瑣細節。我們需要乙個好的封裝。

封裝可以使用c或者c++。此處,我按照unix的傳統,提供乙個類似於posix標準中popen/pclose函式呼叫的c封裝,以保證最大程度的可用性。介面如下:

file *dpopen(const char *command);

int dpclose(file *stream);

int dphalfclose(file *stream);

關於介面,以下幾點需要注意一下:

具體的實現請直接檢視程式源**,其中有詳細的注釋和doxygen文件注釋 (6)。我只略作幾點說明:

下面的**展示了乙個簡單例子,將多行文字送到sort中,然後取回結果、顯示出來:

#include #include #include "dpopen.h"

#define maxline 80

int main()

fprintf(fp, "orange\n");

fprintf(fp, "pear\n");

if (dphalfclose(fp) < 0)

for (;;)

dpclose(fp);

return 0;

}

輸出結果為:

orange

pear

回頁首

總結本文闡述了乙個使用socketpair系統呼叫在linux上實現雙向程序通訊管道的方法,並提供了乙個實現。該實現提供的介面與posix規範中的popen/pclose函式較為接近,因而非常易於使用。該實現沒有使用平台相關的特性,因而可以不加修改或只進行少量修改即可移植到支援socketpair呼叫的posix系統中去。

Linux 上實現雙向程序間通訊管道

級別 中級 吳詠煒 adah sh163.本文闡述了乙個使用 socketpair 系統呼叫在 linux 上實現雙向程序通訊管道的方法,並提供了乙個實現。問題和常見方法 linux 提供了 popen 和 pclose 函式 1 用於建立和關閉管道與另外乙個程序進行通訊。其介面如下 file po...

程序間通訊 雙向管道實現

linux 提供了 popen 和 pclose 函式 1 用於建立和關閉管道與另外乙個程序進行通訊。其介面如下 file popen const char command,const char mode int pclose file stream 遺憾的是,popen 建立的管道只能是單向的 m...

Linux 管道 實現程序間通訊

管道是一種最基本的 ipc 機制,由 pipe 函式建立 include int pipe int filedes 2 呼叫 pipe 函式時在核心中開闢一塊緩衝區 稱為管道 用於通訊,它有乙個讀端乙個寫端,然後通過 filedes 引數傳出給使用者程式兩個檔案描述符,filedes 0 指向管道的...