美文网首页
图解系统 I/0 结构

图解系统 I/0 结构

作者: 微微笑的蜗牛 | 来源:发表于2020-10-17 20:36 被阅读0次

    在 linux 中,一切皆文件,比如磁盘、网络、管道等等。文件是一切 IO 设备的抽象,屏蔽了底层复杂的实现。在编写代码时,我们最常接触是就是文件描述符,通过它来操作文件的读写,关闭等。那么文件描述符到底是啥呢?

    文件描述符

    当打开一个文件时,会返回 fd 文件描述符。它其实就是一个整数,为文件描述符表的下标。系统中有三个默认的 fd,分别为标准输入、标准输出、标准错误。之后打开的文件描述符从 3 开始。

    • std_in,标准输入,fd = 0
    • std_out,标准输出,fd = 1
    • std_err,标准错误,fd = 2

    三张表

    文件描述符表中的每一项指向打开文件列表中的文件,包括当前文件偏移量、文件的引用计数、文件的 inode 指针。

    其中 inode 指针指向一个结构,表示文件的一些元信息,比如文件大小、类型、创建时间、修改时间等等。另外这里还涉及到另外一个表,v-node 表,用来存储 inode 节点信息,包括 stat 结构中的大多数信息。

    简单来说,这里会涉及到三张表:

    • 文件描述符表,每项指向文件表中的一项。
    • 打开的文件表,存放文件当前位置、引用计数、inode 指针。
    • v-node 表,存放 inode 节点信息。

    数据结构如下图所示:

    Xnip2020-10-17_14-25-57.jpg

    文件共享

    这种结构可以十分方便的引用同一个文件,实现文件共享。

    当多次打开同一个文件时,会生成不同的 fd,指向文件表中的不同的项,各自记录文件位置,便于独立读写。但 inode 信息是指向同一份,在一定程度上也节约了资源。如下图所示:

    Xnip2020-10-17_14-26-13.jpg

    进程共享

    文件描述符表在每个进程中会单独维护一份,而打开文件表和 v-node 表则是进程间共享的。

    当调用 fork 创建子进程时,子进程会 copy 父进程的文件描述符表,继承父进程所有打开文件的信息。但文件表和 v-node 表还是同一份。如下图所示:

    Xnip2020-10-17_14-34-56.jpg

    文件关闭

    当关闭某个文件时,文件的引用计数会减 1。当文件的引用数为 0 时,则与该文件相关的数据结构会被销毁,即打开文件列表中的数据和 inode 数据。此时,该 fd 便可重用了。见下图。

    Xnip2020-10-17_15-00-28.jpg

    I/O 重定向

    I/O 重定向可将标准输入输出与磁盘文件联系起来。

    比如 ls > output.txt,可将标准输出重定向到 output.txt 中。那么它到底是如何实现的呢?

    linux 中提供了 dup2(oldfd, newfd) 函数来进行重定向,dup2 表示 duplicate,含义是复制一个已存在的文件描述符。具体实现原理如下:

    newfd 在文件描述符表中的项替换为 oldfd 的项,如果 newfd 已经被打开,则需要先关闭。

    更加详细的信息可以查看 man dup2

    举个栗子。比如 dup2(3, 1),表示将标准输出 fd1 重定向到 fd3 这个描述符上。

    假设 fd1 和 fd3 原来的指向如下图所示:

    Xnip2020-10-17_14-25-57.jpg

    当调用 dup2(3, 1) 后,数据结构如下图所示:

    Xnip2020-10-17_14-25-35.jpg

    由于 fd1 之前有指向打开的文件,因此它会先被关闭,该文件的引用计数变为 0。此时,文件表中的该项和对应 v-node 表中的项(白色边框部分)会被删除掉,并且 fd1 重新可复用。

    相关文章

      网友评论

          本文标题:图解系统 I/0 结构

          本文链接:https://www.haomeiwen.com/subject/lxvfmktx.html