在linux中,進程的通信可以通過信號量,互斥量來進行交流,但這些變量只是一個簡單的數據結構,而不是一組數據字符串,所以通信過程變得複雜,而且效率不高。
爲了使得進程間的通信變得更加方便,便引入了管道(pipe)這一功能。通常把一個進程的輸出通過管道鏈接到另一個進程的輸入。
在shell命令中,命令的連接通過管道字符(‘ | ’)來完成的,比如:
cmd1 | cmd2
cmd1的標準輸入來自終端鍵盤;cmd1的標準輸出傳遞給cmd2,作爲它的標準輸入;cmd2的標準輸出連接到終端屏幕。
在程序之間傳遞數據的常用方法就是使用popen和pclose兩個功能函數。它們的定義如下:
#include<stdio.h>
FILE *popen(const char *command,const char *open_mode);
int pclose(FILE *stream_to_close);
popen函數:
它允許一個程序將另一個程序作爲新的進程來啓動,並可以傳遞數據給它或者通過它接收數據。command參數是要運行的程序和相應的參數着一組數據的字符串。open_mode必須是“r”或者是"w"。如果是“r”,被調用程序的輸出就可以讓調用程序使用,調用程序利用popen函數返回的*FILE文件流指針,就可以通過常用的stdio庫函數(如fread)來讀取被調用程序的輸出。如果是“w”,調用程序就可以用fwrite調用向被調用程序發送數據,而被調用程序可以在自己的標準輸入上讀取這些數據。
pclose函數:
pclose調用只在popen啓動的進程結束後才返回u。如果調用pclose時它仍在運行,pclose調用將等待該進程的結束。如果調用進程在調用pclose之前執行了一個wait語句,被調用進程的退出狀態就會丟失,因爲被調用進程已結束。此時,pclose將返回-1並設置errno爲ECHILD。
下面通過2個例子介紹popen和pclose的具體使用。
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define BUFSIZ 1024
int main()
{
FILE *read_fp;
char buffer[BUFSIZ+1];
int chars_read;
memset(buffer,'\0',sizeof(buffer)); //初始化數組buffer全爲空。
read_fp=popen("uname -a","r"); //"read_fp"指向從"uname -a"讀出來的信息的首地址。
if(read_fp!=NULL) { //read_fp不爲空則說明讀到了信息。
chars_read=fread(buffer,sizeof(char),BUFSIZ,read_fp);//fread返回的值爲讀到的字節數,所以用int類型的變量接收。
if(chars_read>0) {
pritf("output was:-\n%s\n",buffer);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
該程序運行的結果是現實計算機以及操作系統的相關信息。這段代碼展示了調用程序利用popen將被調用程序的輸出作爲自己的輸入。
例子2:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define BUFSIZ 1
int main() {
FILE *write_fp;
char buffer[BUFSIZ+1];
sprintf(buffer,”once upon a time,there was...\n”); //在buffer中寫入這一字符串。
write_fp=popen(“od -c”,”w”); //write_fp指向“od -c”讀取的信息的首地址。
if(write_fp!=NULL) {
fwrite(buffer,sizeof(char),strlen(buffer),write_fp); //將write_fp指向的信息寫入buffer當中。
pclose(write_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
這段代碼顯示的那串字符存儲的地址。調用程序把自己的輸出利用popen函數作爲了被調用程序的輸入。
請求popen調用運行一個程序時,首先要啓動shell,即系統中的sh命令。爲了省略掉啓動shell,節省空間 ,還有對數據的控制,一般使用pipe函數來讓兩個程序之間傳遞數據。
pipe函數的原型如下:
#inclde<unistd.h>
int pipe(int file_descriptor[2]);
pipe函數中的參數是有兩個整數類型的文件描述符組成的數組的指針。該函數在數組中填入兩個新的文件描述符後返回0,如果失敗則返回-1並設置errno來表明失敗原因。
兩個返回的文件描述符以一種特殊的方式連接起來。寫到file_descriptor[1]的所有數據都可從file_descriptor[0]中讀回來。其中數據是按照先進先出的原則處理的。
通過例子說明pipe的使用:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define BUFSIZ 1024
int main() {
int data_processed;
int file_pipes[2]; //定義了pipe函數需要的參數。
const char some_data[]=”123”;
char buffer[BUFSIZ+1];
memset(buffer,’\0’,sizeof(buffer)); //設置buffer爲空。
if(pipe(file_pipes)==0) { //pipe函數返回0,則運行正確。
data_processed=write(file_pipes[1],some_data,strlen(some_data); //將some_data中的數據寫入file_pipes[1]中。
printf(“wrote %d bytes\n”,data_processed);
data_processed=read(file_pipes[0],buffer,BUFSIZ); //將file_pipes[0]中的數據讀入buffer。
printf(“read %d bytes: %s\n”,data_processed,buffer);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}