進程之間的通信--管道

在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 1int 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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章