您的位置:首页 > 理论基础 > 计算机网络

http://blog.sina.com.cn/s/blog_641926f30100trj1.html popen/pclose解析

2015-10-02 09:43 411 查看


popen/pclose解析

(2011-06-11 21:30:04)


转载▼

标签:


linux


c语言


pclose


popen


杂谈

blogbus抽风了,暂时贴到这里吧。。。囧。。。

--------------------------------------分割线-----------------------------------------

popen()

度娘是这样解释的:

表头文件

  #include

函数定义

  FILE * popen ( const char * command , const char * type );

  int pclose ( FILE * stream );

函数说明

  popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。这个进程必须由pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。

  type 参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 "r" 则文件指针连接到 command 的标准输出;如果 type 是 "w" 则文件指针连接到 command 的标准输入。

  command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用-c 标志,shell 将执行这个命令。

  popen 的返回值是个标准 I/O 流,必须由 pclose 来终止。前面提到这个流是单向的。所以向这个流写内容相当于写入该命令的标准输入;命令的标准输出和调用 popen 的进程相同。与之相反的,从流中读数据相当于读取命令的标准输出;命令的标准输入和调用 popen 的进程相同。

看完度娘的解释,我更迷糊了。。。popen会调用fork函数建一个子进程,然后捏,然后他干了什么捏,肿么结束的捏,pclose都终止了什么捏。。。算了,还是自己动手丰衣足食吧。

现在的主要问题有2个,1.popen是否会创建一个进程 2.pclose都干了什么。这对这个问题写了个小程序来观察下mian函数贴一下:

void main()

{

FILE *fp;

fp=popen("ls","r"); //这里随意写

printf("popen!\n");

sleep(3);

pclose(fp);

printf("pclose!\n");

sleep(3);

}

在2个printf后在终端输入 ps au,观察进程。发现在popen后出现了一个叫[sh] 的进程,在pclose后这个进程就被杀死了。由此看来,popen确实调用fork产生了一个新的进程,而这个新的进程在执行了popen里面的参数命令后,就变成了defunct(僵尸进程)。

所谓僵尸进程,应该和孤儿进程一同记忆。顾名思义,孤儿进程就是父进程已死,僵尸进程则是子进程已死,但是父进程依然运行。僵尸进程的危害是非常大的,因为父进程没有替子进程“收尸”,导致其在进程表(process table)中仍然占有一个位置(slot)。由于进程表资源是有限的,最终会影响系统性能,甚至是使系统瘫痪。孤儿进程则无需担心,因为孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程将会导致资源浪费,而孤儿进程则不会。

显然在popen创建的进程在父进程之前结束,并且成为了僵尸进程,还可以看出pclose绝对不是仅仅关闭管道,还要对僵尸进程进行收尸!

本身觉得文章写到这就可以结束了,但是无意间看到了这篇blog:点这里,给了我一个提示,可以看看popen和pclose的源码,从根本解决下问题。给出核心代码。

popen:

if ( (pid = fork()) == -1 ){

close(pfp[0]);

close(pfp[1]);

return NULL;

}

在这里先fork了一次,如果错误,则关闭管道读写口,然后返回。

if ( pid > 0 ){

if (close( pfp[child_end] ) == -1 )

return NULL;

return fdopen( pfp[parent_end] , mode);

}

在父进程中如果打开管道正确,则会与文件描述符一致的文件指针。

if ( close(pfp[parent_end]) == -1 )

exit(1);

if ( dup2(pfp[child_end], child_end) == -1 )

exit(1);

if ( close(pfp[child_end]) == -1 )

exit(1);

execl( "/bin/sh", "sh", "-c", command, NULL );

exit(1);

子进程则会调用execl函数执行shell命令,execl后面的exit(1)是在execl执行失败后才会执行,所以写的是exit(1),源码果真是写的精简却不简单那!!

pclose源码木有找到,囧。。。等找到再分析

找源码还必须翻墙。。。现在开始分析

The code sample below illustrates how the pclose() function might be implemented on a system conforming to IEEE Std 1003.1-2001.

int pclose(FILE *stream)

{

int stat;

pid_t pid;

pid = (void) fclose(stream);

while (waitpid(pid, &stat, 0) == -1) {

if (errno != EINTR){

stat = -1;

break;

}

}

return(stat);

}

果真是有waitpid来为僵尸进程收尸!!源码真是个好东西
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: