1. 文件描述符在内核中数据结构
在具体说dup/dup2之前,我认为有必要先了解一下文件描述符在内核中的形态。一个进程在此存在期间,会有一些文件被打开,从而会返回一些文件描述符,从shell中运行一个进程,默认会有3个文件描述符存在(0、1、2), 0与进程的标准输入相关联,1与进程的标准输出相关联,2与进程的标准错误输出相关联,一个进程当前有哪些打开的文件描述符可以通过/proc/进程ID/fd目录查看。 下图可以清楚的说明问题:
进程表项

————————————————

   fd标志 文件指针

_____________________

fd 0:|________|____________|------------> 文件表

fd 1:|________|____________|

fd 2:|________|____________|

fd 3:|________|____________|

|     .......         |

|_____________________|

图1

文件表中包含:文件状态标志、当前文件偏移量、v节点指针,这些不是本文讨论的重点,我们只需要知道每个打开的文件描述符(fd标志)在进程表中都有自己的文件表项,由文件指针指向。
2. dup/dup2函数
APUE和man文档都用一句话简明的说出了这两个函数的作用:复制一个现存的文件描述符。
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
从图1来分析这个过程,当调用dup函数时,内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。
  进程表项

————————————————

   fd标志 文件指针

_____________________

fd 0:|________|____________|                   ______

fd 1:|________|____________|----------------> |      |

fd 2:|________|____________|                  |文件表|

fd 3:|________|____________|----------------> |______|

|     .......         |

|_____________________|

图2:调用dup后的示意图
如图2所示,假如oldfd的值为1,当前文件描述符的最小值为3,那么新描述符3指向描述符1所拥有的文件表项。
dup2和dup的区别就是可以用newfd参数指定新描述符的数值,如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新文件描述符同样与参数oldfd共享同一文件表项。
APUE用另外一个种方法说明了这个问题:
实际上,调用dup(oldfd)等效于
fcntl(oldfd, F_DUPFD, 0)
而调用dup2(oldfd, newfd)等效于
close(oldfd);
fcntl(oldfd, F_DUPFD, newfd);

实例:

dup 和 dup2 都可以用来复制一个现存的文件描述符。经常用来重新定向进程的 STDIN, STDOUT, STDERR。

dup 函数
dup 函数定义在 <unistd.h> 中,函数原形为: int dup ( int filedes ) ;
函数返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝,若出错则返回 -。由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。这函数返回的新文件描述符与参数 filedes 共享同一个文件数据结构。 dup函数实例:
[lingyun@localhost dup]$ ls
dup.c
[lingyun@localhost dup]$ cat dup.c
/*********************************************************************************
* Copyright: (C) 2013 fulinux<fulinux@sina.com>
* All rights reserved.
*
* Filename: dup.c
* Description: This file
*
* Version: 1.0.0(07/31/2013~)
* Author: fulinux <fulinux@sina.com>
* ChangeLog: 1, Release initial version on "07/31/2013 04:00:06 PM"
*
********************************************************************************/ #include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h> int main(int argc, char* argv[])
{
int fd = open("hello", O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
if(fd < )
{
printf("Open Error!!\n");
return ;
} int nfd = dup(fd);
if(nfd < )
{
printf("Error!!\n");
return ;
} char buf[];
int n; while((n = read(STDIN_FILENO, buf,)) > )
{
if(write(nfd, buf, n) != n)
{
printf("Write Error!!\n");
return ;
}
}
return ; } 上面代码中,nfd 拷贝了 fd,所以 write ( nfd, buf, n ) 这语句写到 nfd 所代表的文件时也就是写到 fd 所代表的文件。程序执行完后可以在相应的目录的hello文件中看到输出。
[lingyun@localhost dup]$ gcc dup.c
[lingyun@localhost dup]$ ls
a.out dup.c
[lingyun@localhost dup]$ ./a.out
hello world
^C
[lingyun@localhost dup]$ ls
a.out dup.c hello
[lingyun@localhost dup]$ cat hello
hello world
[lingyun@localhost dup]$ dup2 函数
dup2 函数定义在 <unistd.h> 中,函数原形为: int dup2( int filedes, int filedes2 )
同样,函数返回一个新的文件描述符,若出错则返回 -。与 dup 不同的是,dup2 可以用 filedes2 参数指定新描述符的数值。如果 filedes2 已经打开,则先将其关闭。如若 filedes 等于 filedes2 , 则 dup2 返回 filedes2 , 而不关闭它。同样,返回的新文件描述符与参数 filedes 共享同一个文件数据结构。 dup2函数实例: [lingyun@localhost dup2]$ ls
dup2.c
[lingyun@localhost dup2]$ cat dup2.c
/*********************************************************************************
* Copyright: (C) 2013 fulinux<fulinux@sina.com>
* All rights reserved.
*
* Filename: dup2.c
* Description: This file
*
* Version: 1.0.0(07/31/2013~)
* Author: fulinux <fulinux@sina.com>
* ChangeLog: 1, Release initial version on "07/31/2013 08:22:19 PM"
*
********************************************************************************/ #include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h> int main(int argc, char* argv[])
{
int fd = open("hello.file", O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR);
if(fd < )
{
printf("Open Error!!\n");
return ;
} int nfd = dup2(fd, STDOUT_FILENO);
if(nfd < )
{
printf("Error!!\n");
return ;
} char buf[];
int n; while((n = read(STDIN_FILENO, buf, )) > )
if(write(nfd, buf, n) != n)
{
printf("Write Error!!\n");
return ;
}
return ;
} 上面的例子使用dup2将标准输出重定向为hello.file文件,如下所示:
[lingyun@localhost dup2]$ ls
dup2.c
[lingyun@localhost dup2]$ gcc dup2.c
[lingyun@localhost dup2]$ ./a.out
hello world
^C
[lingyun@localhost dup2]$ cat hello.file
hello world
[lingyun@localhost dup2]$

转自:http://blog.csdn.net/fulinus/article/details/9669177

linux之dup和dup2函数解析的更多相关文章

  1. dup和dup2函数

    下面两个函数都可用来复制一个现存的文件描述符: #include<unistd.h> int dup(int filedes); int dup2(int filedes,int file ...

  2. dup与dup2函数

    依赖的头文件 #include <unistd.h> 函数定义 int dup(int oldfd); int dup2(int oldfd, int newfd); 函数作用 dup和d ...

  3. dup和dup2函数以及管道的实现

    疑问:管道应该不是这样实现的,因为这要求修改程序的代码 dup和dup2也是两个非常有用的调用,它们的作用都是用来复制一个文件的描述符.它们经常用来重定向进程的stdin.stdout和stderr. ...

  4. 文件I/O(不带缓冲)之dup和dup2函数

    下面两个函数都可用来复制一个现有的文件描述符: #include <unistd.h> int dup( int filedes ); int dup2( int filedes, int ...

  5. Unix 网络编程 dup和dup2函数

    dup和dup2也是两个很实用的调用,它们的作用都是用来复制一个文件的描写叙述符. 它们经经常使用来重定向进程的stdin.stdout和stderr.这两个函数的原形例如以下: #include & ...

  6. dup和dup2函数简单使用

    dup函数 头文件和函数原型: #include <unistd.h> int dup(int oldfd); dup函数是用来打开一个新的文件描述符,指向和oldfd同一个文件,共享文件 ...

  7. Linux 字符设备驱动—— ioremap() 函数解析

    一. ioremap() 函数基础概念 几乎每一种外设都是通过读写设备上的相关寄存器来进行的,通常包括控制寄存器.状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址.根据CPU体系结构的不同, ...

  8. dup和dup2详解

    C语言中dup和dup2函数的不同和使用 发表时间: 2012年11月15日 | 作者: 陈杰斌 | 所属分类: C语言 | 评论: 0 | 浏览: 1024 在unix高级编程中有介绍dup和dup ...

  9. dup和dup2用法小结

    今天和同学探讨了一下关于重定向输出到文件的问题,其中需要用到dup和dup2函数,因此来小小的总结一下. 首先来man一下: dup直接返回一个新的描述符和原来的描述符一样代表同一个资源,描述符的值就 ...

随机推荐

  1. 慕课网SSMOA办公系统

    目录 需求分析 1 用例图 系统设计 包及全局配置 数据库设计 工具类 具体功能实现 1 dao层功能实现 2 编码过滤器及登陆拦截器 3 单元测试 遇到的问题总结 1 新建一个Modul不会打开新页 ...

  2. 使用 ALinq 实现 Linq to MySQL【转】

    http://www.cnblogs.com/huangcong/archive/2011/05/24/2055204.html

  3. 【概率论】4-6:协方差和相关性(Covariance and Correlation)

    title: [概率论]4-6:协方差和相关性(Covariance and Correlation) categories: - Mathematic - Probability keywords: ...

  4. C语言学习笔记10-结构体、枚举、联合体

    C语言学习笔记10-结构体.枚举.联合体    待传

  5. pytest学习笔记(一)

    这两天在学习pytest,之前有小用到pytest,觉得这个测试框架很灵巧,用在实现接口自动化(pytest+requests)非常的轻便,然后很有兴致的决定学习下,然后又发现了pytest-sele ...

  6. 十一、FHS基础原理

      文件系统: http://note.youdao.com/noteshare?id=298f02714da5b9483429a40dda667f35&sub=6120396419BA477 ...

  7. HDU 1087 Super Jumping! Jumping! Jumping! ——(LIS变形)

    和之前那个长方体最大高度是换汤不换药的题目.每次找之前最大的一个能接的接上即可.代码如下: #include <stdio.h> #include <algorithm> #i ...

  8. Selenium处理页面懒加载方法

    在做selenium webdriver  在做UI自动化时,有些页面时使用懒加载的形式显示页面图片,如果在不向下移动滚动条时,获取到的图片会是网站的默认图片和真实的图片不相符. 1.滑动滚动条 1. ...

  9. Redis字符串(String)

    1.set SET key value [EX seconds] [PX milliseconds] [NX|XX] 将字符串值 value 关联到 key 可选参数: EX second :设置键的 ...

  10. 动态连通性问题——算法union-find

    问题定义:问题的输入是一列整数对,其中每个整数都表示一个某种类型的对象,一对整数p,q可以被理解为"p和q是相连的".我们假设“相连”是一种对等的关系. 这也意味着它具有: 1.自 ...