深入dup2的内部细节
2017-05-23 19:15
169 查看
基础信息:
所需头文件:#include <unistd.h>
函数原型:
int dup2(int oldfd, int newfd);
返回值:成功返回新的文件描述符,失败返回-1
功能:将
oldfd描述符复制给
newfd
深入理解:
当我们把oldfd和
newfd传入到
dup2时,到底发生了什么呢?
这里需要用到有关文件方面的知识了,作一个简要的说明(具体请参考我之前的博客http://blog.csdn.net/move_now/article/details/62054836):
内核在表示一个打开的文件时使用了三个数据结构,文件描述符表,文件表以及v节点表。
1. 文件描述符表:每个进程都独有的一张用于存储文件描述符标志和指向文件表某一项的文件指针
2. 文件表:每一项都代表了一个打开的文件,存储的是文件的状态标志以及当前文件的偏移量还有指向v节点表的指针(注意同一文件可以被打开多次)
3. v节点表:存储了v节点的信息(文件类型以及对此文件进行操作的各种函数的指针)和i节点。i节点是在打开文件时从磁盘上读入内存的,里面存储了文件的大量信息,我们平时使用的
ls -l命令读取的信息大部分就是从i节点里面提取出来的。
知道了这些,其实我们调用
dup2之后,相当于
newfd的文件指针被
oldfd的文件指针覆盖了,这样造成的结果就是两者指向同一个文件表项。于是它们共享同一文件的状态标志、偏移量还有指向相同的v节点表以及各种该文件的信息。这就是为什么调用了
dup2之后,两个文件描述符都可以用来访问同一个文件的原因。
细节部分:
接下来有几个问题,如果弄懂了那证明就已经理解了:问题一:当我们使用dup2时,
oldfd是否需要处于打开状态呢?
答案是需要,因为只有打开的文件才会在文件表中占有一项,它的文件指针才有作用,这样赋给
newfd才有意义。
问题二:
newfd是否需要处于打开状态呢?
回答是不需要,就算打开了,也会先被关闭(除非
newfd和
oldfd是相同的文件描述符)。
dup2完成的功能相当于是先调用
close关闭
newfd,然后再调用
fcntl(oldfd, F_DUPFD, newfd),不过
dup2是原子操作。
问题三:既然我们传入处于打开状态的
newfd会被先关闭掉,那么调用了
dup2之后如果再打开一个新的文件,那么
newfd是否会被用于打开的新的文件的描述符呢?
结果是不会,
newfd索引到的文件描述符表非空,是处于被占用状态的,所以不会分配给新的文件。
这里为了加深印象,给出一段测试代码:
#include <iostream> using namespace std; #include <unistd.h> #include <fcntl.h> #include <string> #include <errno.h> #include <stdio.h> #include <stdlib.h> int main() { char s[] = "123123"; int fd = open("test.txt", O_RDWR | O_CREAT, 0644); cout << "fd :" << fd << endl; //fd会先被close掉,不过是在dup2内部完成的 dup2(STDOUT_FILENO, fd); //这里打开了一个新的文件,但是输出发现占用的是fd之后的文件描述符 int fd1 = open("test1.txt", O_RDWR | O_CREAT, 0644); cout << "fd1:" << fd1 << endl; if(write(fd, s, sizeof(s)) < 0) { perror("write error:"); exit(1); } close(fd); close(fd1); return 0; }
题外话:
之前提到了一下文件描述符标志和文件的状态标志。这两者的不同之处其实根据所存储它们的数据结构就可以得到这样的结论:文件描述符标志是仅仅针对文件描述符的,当用另外的文件描述符索引到同一个文件时,该标志在新的文件描述符中就不见了。而文件的状态标志则是针对每个文件的,不管索引到该文件的文件描述符是多少。当我们调用了dup2或者
dup之后,文件描述符标志中的
FD_CLOEXEC标志会被清除掉。
FD_CLOEXEC标志被设置的作用是当我们调用
exec函数簇的时候,对应的设置了该标志的文件描述符会在执行
exec指定的文件前被关闭。
具体是什么情况由于和我们的目的不同,就不在这里阐述了。(当我们调用
exec之后,不相让
exec执行的程序访问原来进程打开的文件描述符所指向的文件时,就应该设置该标志)。
相关文章推荐
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 深入理解ASP.NET的内部运行机制(转)
- [你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器
- Android 属性动画 源码解析 深入了解其内部实现
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 【深度学习:CNN】深入理解CNN的细节 (1)
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 深入相关算法,协同过滤:探索推荐引擎内部的秘密(2)
- 夜观星象-深入数据库连接池内部运转原理
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤
- 深入研究 蒋金楠(Artech)老师的 MiniMvc(迷你 MVC),看看 MVC 内部到底是如何运行的
- Kafka学习(三):Kafka的内部机制深入(持久化,分布式,通讯协议)
- 深入分析ENode的内部实现流程和关键地方的幂等设计
- Android 深入了解相册内部 一
- [ExtJS5学习笔记]第三节 sencha cmd学习笔记 生成应用程序构建的内部细节