[linux]文件描述符再探

来源:互联网 发布:多样性指数分析软件 编辑:程序博客网 时间:2024/06/06 00:26

第一点也是最重要的一点:在linux上所有的硬件挂载/dev/mouse,pipe,文件,socket等都是文件!都是可以通过文件描述符来访问到的。


文件描述符file descriptor:是一个对文件的索引号,可以认为是一个公司里面的员工id号,通过id可以索引到员工,然后对员工进行一些操作。

首先要理解文件描述符,得有如下3个内核所维护的数据结构概念:

1.进程级的文件描述符

2.系统级的打开文件表

3.文件系统的i-node表


进程级的文件描述符:

针对于每一个进程,内核都会维护打开文件的描述符表,表中的每一条记录都记录了单个文件的相关信息,控制文件描述操作的标志,对打开句柄的引用,这里的句柄是指系统级打开文件表中的条目。


系统级的打开文件表

内核对所有打开的文件维护一个系统级的文件打开表,并将表中的各条目称之为打开句柄。一个句柄存储了打开文件的相关信息。包括文件偏移,打开文件状态flags,文件的访问模式,信号驱动I/O相关设置,对文件系统中的i-node的引用。


文件系统的i-node表:

目前linux的文件系统已经到了ext4,想知道自己系统的文件系统是什么 可以使用

df -aT
进行查看。一个文件在linux中可以有属性,权限,数据信息。ext文件系统通畅将这两部分的数据分别存放在不同的快,权限和属性放在inode中,实际数据则放在data block中。

一个文件会占用一个inode,inode记录文件的数据所在的block号码。如下图所示:


假设一个文件存放在inode4号,而这个文件实际放在了2,7,13,15这四个data block中,此时操作系统读出四个block就能将文件内容读出。




在程序中一个默认使用了3个文件描述符 0 ~ 2, 标准输入输出错误:STDIN_FILENO = 0,STDOUT_FILENO = 1,STDERR_FILENO = 2。

当用

int open(char* name,int flags,.../* mode_t mode */);
当开一个文件的时候,会返回最低的未使用的文件描述符序号,当标准输入,输出,错误被占用的情况下,将返回3;


上图中进程A的文件描述符fd 1 和 20是指向同一个句柄,这可能是因为使用了dup(),dup2(),fcntl()函数产生的

进程A的文件描述符 fd 2和 进程B的文件描述符 fd 2都指向同一个句柄,这可能是因为执行fork()之后,产生的内存拷贝,即A和B是父子进程关系,继承来的。

进程A的文件描述符 fd 0 和 进程B的文件描述符 fd 3 指向不同的句柄,但是指向同一个inode,可能是因为都打开了同一个文件,同一个进程两次打开一个文件也会发生这种情况。


总结:两个不同的文件描述符,若指向同一个打开文件句柄,则共享偏移,即通过一个文件描述符更改内容,另外一个文件描述符也是可以观察到的。


那么两条命令行

./run_script >result.log 2>result.log./run_script >result.log 2>&1

第一条命令行 相当于 创建了两个文件描述符,但是不共享句柄,即偏移不共享,这就会产生十分怪异的情况,即输出结果是乱序的

第二条命两行 将文件描述符复制标准输入文件描述符,共享句柄,共享偏移,输出结果和控制台输出结果是一致的。

复制描述符 可以用

int dup(int oldfd);int dup2(int oldfd,int newfd);

dup()函数会复制一个文件描述符,返回一个指向相同句柄的新文件描述符,新文件描述符从最低未使用的描述符选择。

比如:

close(STDIN_FILENO);newfd = dup(STDOUT_FILENO);
这个时候 newfd就是0。因为标准输入所占用的文件描述符为0,这个时候关闭了,0变成未使用,那么dup之后将使得newfd将变成0即最小未使用的文件描述符。

dup2()所执行的功能即 若是指定的新的文件描述符存在,则关闭,然后返回,否则直接返回。




1 0
原创粉丝点击