进程间通信(二)popen/pclose

popen其实就是获取一个外部程序的标准输出的的函数,整个调用过程如下所示:
popen实现过程

打开一个shell
运行程序
暂存至管道
返回管道描述符

他是一种进程间通信方式,通过创建的管道完成外部程序信息的传递,优点是能够利用到强大的shell,缺点是额外启动shell成本较高,单向读写

在Linux系统提供的函数中execl也可以用来启动一个新的进程,可以调用一个外部程序到当前的进程空间里,但是不是一个新的进程。int system(const char * string);也可启动一个shell。

一、什么是管道

管道是连接两个进程的介质,进程A数据通过管道流入进程B。对于Linux用户而言,对下面的语句都不会陌生:

cmd1|cmd2

管道与缓冲区非常相似,cmd1的输出结果将会存放在管道中,管道再转发这个输出结果,对于cmd2而言,转发的内容为输入。

二、最简单的popen

popen简单来说就是打开一个终端并运行指定程序,将其输出放入管道,返回一个指针方便取出管道内容。

#include <stdio.h>
FILE * popen(const char * command, const char * open_mode);
int pclose(FILE * stream_to_close);

输入参数

  • const char * command 是一个shell命令或者程序;
  • const char * open_mode 取值"r"或"w”

返回值

  • FILE * fp 根据open_mode决定这个文件指针可以读还是写

三、例子

3.1 传递一小段数据
//test.cpp
#include <unistd.h>
#include <stdlib.h>
#inlcude <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
    FILE * read_fp=popen("./app","r");
    if(!read_fp) cout<<"pipe open failed"<<endl;//BUFSIZ是默认缓冲区大小

    char data[BUFSIZ+1];
    memset(data,'\0',sizeof(data));
    int chars_read=fread(data,sizeof(char),BUFSIZ,read_fp);//从标准输出打印,fread(名字,单位,长度,文件流)
    if(chars_read>0)
    {
        printf("read data from app, message is :%s",data);
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
//app.cpp
#include <stdlib.h>
#include <stdio.h>

int main()
{
    double pi=3.141592653;
    printf("%lf",pi);//该进程标准输出
}

进行编译产生两个应用程序test和app。

g++ test.cpp -o test
g++ app.cpp -o app

运行./test,将会在shell启动app并将在test中使用app的输出,可以看出两个进程如果需要双向通信需要用到两个管道。

3.2 传递更多数据

上面的例子都只是将所有数据通过一次fread和fwrite来调用或接收,有时候我们希望能以块形式发送数据,或者我们根本不知道输出数据的长度,为了避免定义一个非常大的缓冲区,我们可以用多个fread和fwrite将调用数据分为几部分处理。

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    FILE * read_fp;
    char buffer[BUFSIZ+1];//留下一个作为\0终止符存储
    int chars_read;
    memset(buffer,'\0',sizeof(buffer));
    read_fp=popen("ps ax","r");//打开另一个程序
    if(read_fp!=NULL)//成功打开指定程序
    {
        chars_read=fread(buffer,sizeof(char),BUFSIZ,read_fp);//fread返回实际读到的数量
        while(chars_read>0)//只要有数据可读,一直进行下去
        {
            buffer[chars_read-1]='\0';//处理成C字符串
            printf("Reading %d: -n\n %s\n",BUFSIZ,buffer);
            chars_read=fread(buffer,sizeof(char),BUFSIZ,read_fp);
        }
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}
3.3 popen执行shell命令
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    FILE * read_fp;
    char buffer[BUFSIZ+1];
    int chars_read;

    memset(buffer,'\0',sizeof(buffer));
    read_fp=popen("cat *.h|wc -l","r");
    if(read_fp!=NULL)
    {
        chars_read=fread(buffer,sizeof(char),BUFSIZ,read_fp);
        while(chars_read>0)
        {
            buffer[chars_read-1]='\0';
            printf("Reading %d: -n\n %s\n",BUFSIZ,buffer);
            chars_read=fread(buffer,sizeof(char),BUFSIZ,read_fp);
        }
        pclose(read_fp);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}

wc -l将会统计输出指定文件的行数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值