進程之間的通信——管道

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