免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 720 | 回复: 0
打印 上一主题 下一主题

再读管道 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-10 10:26 |只看该作者 |倒序浏览

                                                                                本来刚才已经些好了的,但是对页面进行修改的时候不小心点成了删除,现在又得重新写一遍了,下次坚决在odt
里面写好在copy过来,这给了我一个教训。
昨天对管道的通信又进行了一次复习,这次复习然我对管道有了一个新的认识和了解。特别是对于管道的重定向问
题,在对shell的重定向时通过相关的系统调用来实现重定向。
小组在讨论时对如下问题还存在不清楚的地方:
1、pipe调用的数组,如果定义为 int fd[3]或者fd[n]等,会有什么结果?
这个对pipe的操作应该没影响,fd[0]、fd[1]未发生变化。前两个是管道的文件描述符,后面不动~道理很简
单,数组在作为实参时会退化为指针。但是如果调用fd[1]以后的就会出现进程件不能通信,后面的都不是管道的
文件描述符。
2、如果先fork()再pipe()是什么样子?
会在两个进程中分别开管道,而两个管道没有什么关系。道理很显而易见,fork时子进程会自动获得父进程的
文件描述符,而fork后,它们就行为独立,谁再打开某个文件是互相没有关系的。执行pipe的进程创建了一个
管道文件,如果子父进程都执行了,那就分别有一个管道,子父进程虽然都使用了fd但仅仅是名字相同,分别
对应不同的数据。子父进程不“共用”变量。
3、管道的功能仅仅是实现父子进程之间的通信吗?
管道要看是无名管道还是有名管道了,无名管道是实现具有亲缘关系的进程间相互的通信。而有名管道可以进
行没有亲缘关系间的进程间的通信,当然了,有名管道也可以进行具有亲缘关系的进程进行通信,之所以在具
有亲缘关系件的进程没有采用,我想是因为太过于麻烦,直接有pipe()就可以了。
4、popen()函数,这个函数的实现过程?
我们的讨论结果是 pipe()-->fork()-->dup2-->exec
这个给我的感觉就好像是对上述几个函数的封装,但是又不是不完全的封装,他先pipe创建一个单向通信的管
道,并调用fork创建一个新的子进程。至于后面的dup或者是exec等函数就得看源码 ,看是否有重定向,创
建的子进程是否有进行写的必要。因为fork函数创建子进程时,子进程并不复制父进程相关资源,父子进程通
过访问相同的物理内存来伪装已经实现了对资源的复制,这种共享方式用于只读。子进程写的话,可能就要改
变子进程的一些数据断之类的,这时会调用exec等函数。
摘自:
http://groups.google.com/group/xiyoulinux/browse_thread/thread/71067cad325f722?hl=zh-CN

有一定的改动
另外,在实现管道间的双向通信时,如果创建两个管道,那样的通信方式感觉太过麻烦,使用pipe就只能如此
了。不过,Linux实现了一个源自BSD的socketpair调用,可以实现上述在同一个文件描述符中进行读
写的功能(该调用目前也是POSIX规范的一部分)。该系统调用能创建一对已连接的(UNIX族)无名
socket。在Linux中,完全可以把这一对socket当成pipe返回的文件描述符一样使用,唯一的区别就是这一
对文件描述符中的任何一个都可读和可写。

似乎可以是一个用来实现进程间通信管道的好方法。不过,要注意的是,为了解决我前面的提出的使用
sort的应用问题,我们需要关闭子进程的标准输入通知子
进程数据已经发送完毕,而后从子进程的标准输出
中读取数据直到遇到EOF。使用两个单向管道的话每个管道可以单独关闭,因而不存在任何问题;而在使用双

管道时,如果不关闭管道就无法通知对端数据已经发送完毕,但关闭了管道又无法从中读取结果数据。——
这一问题不解决的话,使用socketpair的设想
就变得毫无意义。
                       
      
令人高兴的是,shutdown调用可
解决此问题。毕竟socketpair产生的文件描述符是一对socket,socket
上的标准操作都可以使用,其中也包括shutdown。——利用
shutdown,可以实现一个半关闭操作,
通知对端本进程不再发送数据,同时仍可以利用该文件描述符接收来自对端的数据。没有错误检测的
代码示意如下:
                       
      
                       
      int fd[2];
pid_t pid;
socketpair(AF_UNIX, SOCKET_STREAM, 0, fd);        // 创建管道
if ( (pid = fork()) == 0) {        // 子进程
    close(fd[0]);        // 关闭管道的父进程端
    dup2(fd[1], STDOUT_FILENO);        // 复制管道的子进程端到标准输出
    dup2(fd[1], STDIN_FILENO);        // 复制管道的子进程端到标准输入
    close(fd[1]);        // 关闭已复制的读管道
    /* 使用exec执行命令 */
} else {        // 父进程
    close(fd[1]);        // 关闭管道的子进程端
    /* 现在可在fd[0]中读写数据 */
    shutdown(fd[0], SHUT_WR);        // 通知对端数据发送完毕
    /* 读取剩余数据 */
    close(fd[0]);        // 关闭管道
    /* 使用wait系列函数等待子进程退出并取得退出代码 */
}
很清楚,这比使用两个单向管道的方案要简洁不少。
                       
      
文章后半部分管道间的双向通信实现摘自:
http://www.ibm.com/developerworks/cn/linux/l-pipebid/index.html
               
               
               
               
               
               
               
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/74012/showart_1119629.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP