免费注册 查看新帖 |

Chinaunix

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

理解dup和dup2 [复制链接]

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

看到ChinaUnix(CU)上的一个帖子后,觉得自己对dup和dup2特别是后者的理解还是有欠缺的,这两个接口看起来很简单,但是理解起来也真的并不是那么容易。
相信大部分在Unix/Linux下编程的程序员手头上都有《Unix环境高级编程》(APUE)这本超级经典巨著。作者在该书中讲解dup/dup2之前曾经讲过“文件共享”,这对理解dup/dup2还是很有帮助的。这里做简单摘录以备在后面的分析中使用:
Stevens said:
(1) 每个进程在进程表中都有一个记录项,每个记录项中有一张打开文件描述符表,可将视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
   (a) 文件描述符标志。
   (b) 指向一个文件表项的指针。
(2) 内核为所有打开文件维持一张文件表。每个文件表项包含:
   (a) 文件状态标志(读、写、增写、同步、非阻塞等)。
   (b) 当前文件位移量。
   (c) 指向该文件v节点表项的指针。
图示:
   文件描述符表
   ------------
fd0  0   | p0  -------------> 文件表0 ---------> vnode0
   ------------
fd1  1   | p1  -------------> 文件表1 ---------> vnode1
   ------------
fd2  2   | p2  
   ------------
fd3  3   | p3  
   ------------
... ...
... ...
   ------------
一、单个进程内的dup和dup2
假设进程A拥有一个已打开的文件描述符fd3,它的状态如下:
  进程A的文件描述符表(before dup2)
   ------------
fd0  0   | p0  
   ------------
fd1  1   | p1  -------------> 文件表1 ---------> vnode1
   ------------
fd2  2   | p2  
   ------------
fd3  3   | p3  -------------> 文件表2 ---------> vnode2
   ------------
... ...
... ...
   ------------
经下面调用:
n_fd = dup2(fd3, STDOUT_FILENO);后进程状态如下:
进程A的文件描述符表(after dup2)
   ------------
fd0  0   | p0  
   ------------
n_fd 1   | p1  ------------
   ------------               \
fd2  2   | p2                 \
   ------------                 _\|
fd3  3   | p3  -------------> 文件表2 ---------> vnode2
   ------------
... ...
... ...
   ------------
解释如下:
n_fd
= dup2(fd3,
STDOUT_FILENO)表示n_fd与fd3共享一个文件表项(它们的文件表指针指向同一个文件表项),n_fd在文件描述符表中的位置为
STDOUT_FILENO的位置,而原先的STDOUT_FILENO所指向的文件表项被关闭,我觉得上图应该很清晰的反映出这点。按照上面的解释我们
就可以解释CU中提出的一些问题:
(1) "dup2的第一个参数是不是必须为已打开的合法filedes?" -- 答案:必须。
(2) "dup2的第二个参数可以是任意合法范围的filedes值么?" -- 答案:可以,在Unix其取值区间为[0,255]。
另外感觉理解dup2的一个好方法就是把fd看成一个结构体类型,就如上面图形中画的那样,我们不妨把之定义为:
struct fd_t {
int index;
filelistitem *ptr;
};
然后dup2匹配index,修改ptr,完成dup2操作。
在学习dup2时总是碰到“重定向”一词,上图完成的就是一个“从标准输出到文件的重定向”,经过dup2后进程A的任何目标为STDOUT_FILENO的I/O操作如printf等,其数据都将流入fd3所对应的文件中。下面是一个例子程序:
#define TESTSTR "Hello dup2\n"
int main() {
        int     fd3;
        fd3 = open("testdup2.dat", 0666);
        if (fd  文件表1 ---------> vnode1
   ------------                 /|
fd2  2   | p2               /
   ------------             /
fd3  3   | p3  -------------> 文件表2 ---------> vnode2
   ------------          /
s_fd 4   | p4  ------/  
   ------------
... ...
... ...
   ------------
调用dup2后状态为:
进程A的文件描述符表(after dup2)
   ------------
fd0  0   | p0  
   ------------
n_fd 1   | p1  ------------
   ------------               \
fd2  2   | p2                \
   ------------                _\|
fd3  3   | p3  -------------> 文件表2 ---------> vnode2
   ------------
s_fd 4   | p4  ------------->文件表1 ---------> vnode1
   ------------
... ...
... ...
   ------------
dup(fd)的语意是返回的新的文件描述符与fd共享一个文件表项。就如after dup图中的s_fd和fd1共享文件表1一样。
确定第二个方案后重定向后的恢复就很容易了,只需调用dup2(s_fd, n_fd);即可。下面是一个完整的例子程序:
#define TESTSTR "Hello dup2\n"
#define SIZEOFTESTSTR 11
int main() {
        int     fd3;
        int     s_fd;
        int     n_fd;
        fd3 = open("testdup2.dat", 0666);
        if (fd3  文件表1 ---------> vnode1
   ------------                            /|\
fd2  2   | p2                            |
   ------------                             |
                                              |
子进程B的文件描述符表                |
   ------------                             |
fd0  0   | p0                            |
   ------------                             |
fd1  1   | p1  ---------------------|
   ------------
fd2  2   | p2  
   ------------
所以恰当的利用dup2和dup可以在父子进程之间建立一条“沟通的桥梁”。这里不详述。
四、小结
灵活的利用dup/dup2可以给你带来很多强大的功能,花了一些时间总结出上面那么多,不知道自己理解的是否透彻,只能在以后的实践中慢慢探索了。
参考资料:
1、《Unix环境高级编程》
               
               
               

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP