进程之间的通信——管道

在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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值