一 管道的作用
通常把一個進程的輸出通過管道連接到另一個進程的輸入。
二 popen和pclose函數
#include <stdio.h> FILE *popen( const char *command, //是要運行的程序名和相應的參數
const char * open_mode //必須是“r”或者“w”,如果是其它值,errno將返回EINVAL
); int pclose(FILE *stream_to_close);
popen() 函數通過創建一個管道,調用 fork 產生一個子進程,執行一個 shell 以運行命令來開啟一個進程。
pclose()調用只在popen啟動的進程結束后才返回,如果調用pclose函數時它仍在運行,pclose調用將等待該進程的結束。
例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < string .h> int main(){ FILE * read_fp; //要讀取的文件描述符 char buffer[BUFSIZ+ 1 ]; //用來存儲讀到的文件信息 int chars_read; //實際讀取的元素個數 memset(buffer, ' \0 ' , sizeof (buffer)); //將數組清零初始化 read_fp =popen( " cat test*.c | wc -l " , " r " ); //創建管道,用于顯示所有test*.c文件的字數 if (read_fp!= NULL){ chars_read =fread(buffer, sizeof ( char ),BUFSIZ,read_fp); //從一個文件流中讀數據,最多讀取count個元素,每個元素size字節,如果調用成功返回實際讀取到的元素個數,如果不成功返回 0 while (chars_read> 0 ){ buffer[chars_read - 1 ]= ' \0 ' ; //清除回車符 printf( " Reading:-\n %s\n " ,buffer); chars_read =fread(buffer, sizeof ( char ),BUFSIZ,read_fp); } pclose(read_fp); //關閉管道 exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); }
使用shell的一個不太好的影響:針對每個popen調用,不僅要啟動一個被請求的程序,還要啟動一個shell,即每個popen調用將多啟動兩個進程。從節省系統資源的角度來看,popen函數的調用成本略高,而且對目標命令的調用比正常方式要慢一些。
三 pipe函數
#include <unistd.h> int pipe( int fd[ 2 ]);
pipe函數的參數是一個由兩個整數類型的文件描述符組成的數組的指針,兩個返回的文件描述符以一種特殊的方式連接起來,寫到fd[1]的所有數據都可以從fd[0]讀回來,數據基于先進先出的原則(FIFO)進程處理。
對一個已關閉寫數據的管道做read調用將返回0而不是阻塞,讀取無效的文件描述符將看作是一個錯誤并返回-1
?
如果跨越fork調用使用管道,就會有兩個不同的文件描述符可以用于向管道寫數據,一個在父進程中,一個在子進程中。只有把父子進程中的針對管道的寫文件描述符都關閉,管道才會被認為是關閉了,對管道的read調用才會失敗。
管道的讀寫規則:
1 從管道中讀取數據
- 如果管道的寫端不存在,則認為已經讀到了數據的末尾,讀函數返回的讀出字節數為0;
- 當管道的寫端存在時,如果請求的字節數目大于PIPE_BUF,則返回管道中現有的數據字節數,如果請求的字節數目不大于 PIPE_BUF,則返回管道中現有數據字節數(此時,管道中數據量小于請求的數據量);或者返回請求的字節數(此時,管道中數據量不小于請求的數據 量)。注:(PIPE_BUF在include/linux/limits.h中定義,不同的內核版本可能會有所不同。Posix.1要求 PIPE_BUF至少為512字節,red hat 7.2中為4096)。
2 從管道中寫入數據
向管道中寫入數據時,linux將不保證寫入的原子性,管道緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據。如果讀進程不讀走管道緩沖區中的數據,那么寫操作將一直阻塞。
注:只有在管道的讀端存在時,向管道中寫入數據才有意義。否則,向管道中寫入數據的進程將收到內核傳來的SIFPIPE信號,應用程序可以處理該信號,也可以忽略(默認動作則是應用程序終止)。
?
例子:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < string .h> int main(){ const char some_data[]= " 123 " ; int file_pipes[ 2 ]; int data_processed; pid_t fork_result; if (pipe(file_pipes)== 0 ){ fork_result = fork(); if (fork_result==(pid_t)- 1 ){ fprintf(stderr, " Fork failure " ); exit(EXIT_FAILURE); } if (fork_result== 0 ){ //子進程 close( 0 ); //關閉標準輸入,即鍵盤輸入 dup(file_pipes[ 0 ]); //復制一個文件描述符 close(file_pipes[ 0 ]); ? //關閉讀操作 close(file_pipes[ 1 ]); //關閉寫操作 execlp( " od " , " od " , " -c " ,( char *) 0 ); //利用od查看特殊格式的文件內容,-c表示ASCII字符或反斜杠序列,(char*)0參數作用是終止被調用程序的參數列表 exit(EXIT_FAILURE); } else { //主進程 close(file_pipes[ 0 ]); data_processed =write(file_pipes[ 1 ],some_data,strlen(some_data)); //寫入數據 close(file_pipes[ 1 ]); printf( " %d - wrote %d bytes\n " ,getpid(),data_processed); } } exit(EXIT_SUCCESS); }
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
