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)转载▼
标签:
|
--------------------------------------分割线-----------------------------------------
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来为僵尸进程收尸!!源码真是个好东西
相关文章推荐
- 几个网络唤醒工具
- 黑马程序员——Java语言:网络编程
- 《深入理解Linux网络技术内幕》阅读笔记(九)
- 基于Heritrix的特定主题的网络爬虫配置与实现
- TCP Replay
- 从HTTP到JDBC完整访问路径日志实现思路
- Linux网络管理工具
- debian连接网络
- HDU 5468 Puzzled Elena (2015年上海赛区网络赛A题)
- [网络和多线程]9、单例模式
- linux网络管理
- TCP/IP详解卷1 读书笔记:第四章 ARP地址解析协议
- tcp报文格式udp报文格式详解
- CG写实数字插画绘画视频教程
- tcp服务的测试程序开源
- http缓存
- HTTPCLIENT POST 模拟有上传文件和文本字段的动态表单
- 计算机网络常识
- linux C守护进程编写http://www.cnblogs.com/ringwang/p/3528093.html
- 黑马程序员-----网络编程