linux popen()函数完全解密

目录

一、基本功能和测试

1.头文件包含

2.函数原型

3.测试代码

二、与system()比较

1.阻塞进程

2.返回值

3.SIGCHLD

4.SIGINT和SIGQUIT

三、相关文章


本文经作者授权转载,

原文链接:https://zhuanlan.zhihu.com/p/457974696

前文深入探讨了system()函数的用法和注意事项,作为它的兄弟函数popen()有什么特殊之处?为什么很多网友和技术大佬都推荐使用它替代system()来使用呢?这就是本文要探讨的内容。

一、基本功能和测试

1.头文件包含

#include <stdio.h>

2.函数原型

3.测试代码

(1)测试目的

测试代码实现对popen执行命令和读/写命令结果的测试。

(2)测试结果分析

测试结果:

(.1)执行ls,并读取它的stdout,打印出来。结果可见,父进程拿到了ls的标准输出,并打印出来了。

(.2)执行./test,并向它的stdin写入字符串。结果可见,./test子进程收到了父进程给他标准输入写入

的字符串。

(3)测试源码

首先我们要写一个测试程序,用来被popen启动,并接收来自popen调用者的标准输入。

这个程序就是:test.c ,编译得到test。

#include <stdio.h>
#include <string.h>
/*
*打印stdin的输入
*用来测试popen的写入功能
*打印来自popen的写入
**/
int main(int argc,char **argv)
{
    char buf[256];
    memset(buf,0,sizeof(buf));
    printf("pls intput:");
    scanf("%s",buf);
    printf("Your input is %s\n",buf);
    return 0;
}

 然后我们再写一个调用popen函数的测试程序wpopen.c,编译得到wpopen,wpopen具有的功能是以'r'或'w'模式调用popen打开另一个应用程序,如果是'r'则从应用程序的标准输出读出内容并打印,如果是'w'则把argv[3]的内容传给应用程序。

/*
*Copyright (c) 2021 hwtech/X_XCoder.
*All rights reserved.
*作者:hwtech/X_XCoder
*微信号:X_XCoder
*博客:https://blog.csdn.net/u013752202
*知乎:https://www.zhihu.com/people/xiao-yuan-50-93-23
*开源协议:
*版权声明:
*  版权归属hwtech/X_XCoder,您可以下载所有源码学习使用,但不能用于商业用途。
*如需在个人项目中使用,需保留该版权声明。作者拥有所有代码版权,及解释权如有建
*议,可以联系作者。
*
******************宏伟精讲-popen使用演示*****************
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc,char **argv)
{
    int ret=0;
    char buf[256];
    if(argc<3){
        printf("Usages: %s cmd r/w\n",argv[0]);
        return -1;
    }
    FILE *pfp=popen(argv[1],argv[2]);
    if(!pfp){
        printf("popen %s error,errno=%d\n",argv[1],errno);
        return 0;
    }
    printf("\n********宏伟精讲-popen使用演示********\n");
    //如果参数2是w,就把参数参传给子进程的stdin
    if('w'==argv[2][0]){
        fprintf(pfp,"%s\n",argv[3]);
    }
    memset(buf,0,sizeof(buf));
    while(fgets(buf,sizeof(buf),pfp)){
        printf("%s",buf);
        memset(buf,0,sizeof(buf));
    }
    ret=pclose(pfp);
    printf("pclose ret  =%d\n",ret);
    //返回值处理
    if(1==ret){
        printf("程序命令为空\n");
    }
    else if(-1==ret){
        printf("创建命令子进程失败\n");
    }
    else if(0x7f00==ret){
        printf("命令错误,无法执行\n");
    }
    else{
        if(WIFEXITED(ret)){
            printf("程序正常结束,返回值:%d\n",WEXITSTATUS(ret));
        }
        else if(WIFSIGNALED(ret)){
            printf("程序被信号杀死,信号值:%d\n",WTERMSIG(ret));
        }
        else if(WSTOPSIG(ret)){
            printf("程序被信号暂停,信号值:%d\n",WSTOPSIG(ret));
        }
    }
    printf("**************************\n\n");
    return 0;
}

二、与system()比较

关于system()详见《linux-api-system研究》一文。

通过文中介绍,我们知道system()函数不仅返回值五花八门,对信号处理也不太好理解。那么popen是否有同样的问题呢?

1.阻塞进程

(1)是否跟system()一样?

答案:不一样。

(2)详述

前面的测试结果可见,popen调用到pclose调用之间的程序没有被阻塞,pclose后面的代码被阻塞了。所以popen不会阻塞调用者进程,但是pclose会阻塞,也就是说popen-pclose把system调用分开了,以便用户在popen后可以继续运行主进程。

2.返回值

(1)是否跟system()一样?

答案:不一样。

(2)详述

popen返回值很简单,要么非NULL,要么NULL。但是要注意,popen返回成功只代表管道创建成功,不能说明命令执行成功,命令执行结果需要通过pclose返回值来判断。

pclose返回值就跟system除开-1,1后一样。也不简单。

3.SIGCHLD

(1)是否跟system()一样?

答案:一样。

(2)详述

system()命令执行的时候会阻塞主进程的SIGCHLD,调用system()之前如果执行signal(SIGCHLD,SIG_IGN),会导致system返回-1,但命令执行成功的情况。

popen会不会呢?

实际测试发现,如果在pclose之前加了signal(SIGCHLD,SIG_IGN),那么pclose也会跟system()一样,无法通过返回值判断命令执行状态。所以SIGCHLD信号处理跟system是一样的

4.SIGINT和SIGQUIT

(1)是否跟system()一样?

答案:不一样。

(2)详述

system()命令执行的时候,主进程无法收到SIGINT和SIGQUIT。

popen会不会呢?

下面测试结果表明,popen执行命令的过程中,主进程可以正常响应SIGINT和SIGQUIT。这点跟system()不一样

三、相关文章

《宏伟精讲·linux system()函数完全解密》

之前一直埋头搞开发,最近开始输出博文,文章观点经实践验证,但仍不能保证百分之百无误,如有建议,欢迎留言指出,一定虚心受教,及时修改。如有疑问,欢迎留言咨询,知无不言。

但求精品,不问数量。博文会持续输出,但更新速度可能较慢,还往海涵。

后续博文,敬请关注,……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值