博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
进程之间的通信——管道
阅读量:4094 次
发布时间:2019-05-25

本文共 3021 字,大约阅读时间需要 10 分钟。

在linux中,进程的通信可以通过信号量,互斥量来进行交流,但这些变量只是一个简单的数据结构,而不是一组数据字符串,所以通信过程变得复杂,而且效率不高。

为了使得进程间的通信变得更加方便,便引入了管道(pipe)这一功能。通常把一个进程的输出通过管道链接到另一个进程的输入。

在shell命令中,命令的连接通过管道字符(‘ | ’)来完成的,比如:

cmd1 | cmd2

cmd1的标准输入来自终端键盘;cmd1的标准输出传递给cmd2,作为它的标准输入;cmd2的标准输出连接到终端屏幕。

在程序之间传递数据的常用方法就是使用popen和pclose两个功能函数。它们的定义如下:

#include
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
#include
#include
#include
#define BUFSIZ 1024int 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
#include
#include
#include
#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
int pipe(int file_descriptor[2]);

pipe函数中的参数是有两个整数类型的文件描述符组成的数组的指针。该函数在数组中填入两个新的文件描述符后返回0,如果失败则返回-1并设置errno来表明失败原因。

两个返回的文件描述符以一种特殊的方式连接起来。写到file_descriptor[1]的所有数据都可从file_descriptor[0]中读回来。其中数据是按照先进先出的原则处理的。
通过例子说明pipe的使用:

#include
#include
#include
#include
#define BUFSIZ 1024int 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);}

转载地址:http://apxii.baihongyu.com/

你可能感兴趣的文章
DES加解密
查看>>
TCP/IP协议三次握手与四次握手流程解析
查看>>
PHP 扩展开发 : 编写一个hello world !
查看>>
inet_ntoa、 inet_aton、inet_addr
查看>>
用模板写单链表
查看>>
用模板写单链表
查看>>
链表各类操作详解
查看>>
C++实现 简单 单链表
查看>>
数据结构之单链表——C++模板类实现
查看>>
Linux的SOCKET编程 简单演示
查看>>
正则匹配函数
查看>>
Linux并发服务器编程之多线程并发服务器
查看>>
聊聊gcc参数中的-I, -L和-l
查看>>
[C++基础]034_C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)
查看>>
C语言内存检测
查看>>
Linux epoll模型
查看>>
Linux select TCP并发服务器与客户端编程
查看>>
Linux系统编程——线程池
查看>>
基于Visual C++2013拆解世界五百强面试题--题5-自己实现strstr
查看>>
Linux 线程信号量同步
查看>>