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. 怎么学好js

    Js给人那种感觉的原因多半是因为它如下的特点: A:本身知识很抽象.晦涩难懂,如:闭包.内置对象.DOM. B:本身内容很多,如函数库.对象库就一大堆. C:混合多种编程思想.它里面不但牵涉面向过程编 ...

  2. AS400上的binary数据显示不出

    1.用DbVisualizer查询,结果免费的版本不支持 DSPFFD查看该table,column的Coded Character Set Identifier(CCSID)是65535,普通的是3 ...

  3. CF940F Machine Learning 带修改莫队

    题意:支持两种操作:$1.$ 查询 $[l,r]$ 每个数字出现次数的 $mex$,$2.$ 单点修改某一位置的值. 这里复习一下带修改莫队. 普通的莫队中,以左端点所在块编号为第一关键字,右端点大小 ...

  4. [Luogu] 跑路

    https://www.luogu.org/problemnew/show/P1613 Floyd判断是否一步到达 将一步到达的连变跑Floyd #include <iostream> # ...

  5. ubuntu14.0 更改默认python为3.5 并安装tensorflow(cpu)

    转:http://blog.csdn.net/qq_27657429/article/details/53482595 第一:安装pip(如果有pip 跳过) #在ubuntu/Linux 64-bi ...

  6. GAN生成式对抗网络(二)——tensorflow代码示例

    代码实现 当初学习时,主要学习的这个博客 https://xyang35.github.io/2017/08/22/GAN-1/ ,写的挺好的. 本文目的,用GAN实现最简单的例子,帮助认识GAN算法 ...

  7. Spring事务管理的一些注意点

    在<Spring Boot事务管理(下)>中,已经介绍了如果在 protected.private 或者默认可见性的方法上使用@Transactional,事务将是摆设,也不会抛出任何异常 ...

  8. Java连接Memcached进行CRUD

    参考这篇博文在本机安装了Memcached 在 Java 中常用的memcached有三个: Memcached Client for Java SpyMemcached XMemcached 这里使 ...

  9. Hadoop环境搭建|第二篇:hadoop环境搭建

    硬件配置:1台NameNode节点.2台DataNode节点 一.Linux环境配置 这里我只配置NameNode节点,DataNode节点的操作相同. 1.1.修改主机名 命令:vi /etc/sy ...

  10. linux 后台 运行

    但是如果终端关闭的话,程序也会终止,那么就要涉及到linux的一个十分强大的命令:screen. 按照我个人的理解,这个命令就是能够在linux中创造出多个终端,在已有的窗口内部再创造更多的窗口,结合 ...