Linux文件描述符

作者: fasionchan | 来源:发表于2016-09-20 22:16 被阅读4986次

    玩转Linux旧群已满,请加新群:278378501。

    Linux通用I/O模型中,I/O操作系列函数(系统调用)都是围绕一个叫做文件描述符的整数展开。这不禁让人产生疑问:这个整数代表什么?一个数值代表一个文件吗?随便传一个整数进去调用可以吗?

    解答以上疑问,需要更深入学习——文件描述符(File Descriptor)。

    图解

    理解具体情况,需要了解由内核维护的3个数据结构:

    • 进程级文件描述符表(file descriptor table)
    • 系统级打开文件表(open file table)
    • 文件系统i-node表(i-node table)

    这3个数据结构之间的关系如下图所示:

    fd-inode-diagram.png

    文件描述符表

    内核为每个进程维护一个文件描述符表,该表每一条目都记录了单个文件描述符的相关信息,包括:

    • 控制标志(flags),目前内核仅定义了一个,即close-on-exec
    • 打开文件描述体指针

    打开文件表

    内核对所有打开的文件维护一个系统级别的打开文件描述表(open file description table),简称打开文件表。表中条目称为打开文件描述体(open file description),存储了与一个打开文件相关的全部信息,包括:

    • 文件偏移量(file offset),调用read()write()更新,调用lseek()直接修改
    • 访问模式,由open()调用设置,例如:只读、只写或读写等
    • i-node对象指针

    i-node表

    每个文件系统会为存储于其上的所有文件(包括目录)维护一个i-node表,单个i-node包含以下信息:

    • 文件类型(file type),可以是常规文件、目录、套接字或FIFO
    • 访问权限
    • 文件锁列表(file locks)
    • 文件大小
    • 等等

    i-node存储在磁盘设备上,内核在内存中维护了一个副本,这里的i-node为后者。副本除了原有信息,还包括:引用计数(从打开文件描述体)、所在设备号以及一些临时属性,例如文件锁。

    场景解析

    上图中,详细描述了两个进程诸多文件描述符,以及相互关系。

    文件描述符复制

    在进程A中,文件描述符1和文件描述符20都指向同一个打开文件描述体(标号23)。这很可能是通过调用dup()系列函数形成的。

    文件描述符复制,在某些场景下非常有用,比如:标准输入/输出重定向。在shell下,完成这个操作非常简单,大部分人都会,但是极少人思考过背后的原理。

    大概描述一下需要的几个步骤,以标准输出(文件描述符为1)重定向为例:

    1. 打开目标文件,返回文件描述符n;
    2. 关闭文件描述符1;
    3. 调用dup将文件描述符n复制到1;
    4. 关闭文件描述符n;

    子进程继承文件描述符

    进程A的文件描述符2和进程B的文件描述符2都指向同一个打开文件描述体(标号23)。这种情形很可能发生在调用fork()派生子进程之后,比如A调用fork()派生出B。这时,B作为子进程,从父进程A继承了文件描述符表,其中包括图中标明的文件描述符2。这就是子进程继承父进程打开的文件这句话的由来。

    当然了,进程A通过Unix套接字将一个文件描述符传递给B也会出现类似的情形,但一般文件描述符数值是不一样的。同时为2要非常凑巧才发生。

    本文已迁移至:Readthedocs
    更多文章请访问:学习Linux

    相关文章

      网友评论

      • 一粒栗:最后一小节,“进程A的文件描述符2和进程B的文件描述符2都指向同一个打开文件描述体(标号23)。”应该是73才对
        fasionchan:已修正,多谢。
      • 631810aa317a:弱智小白求解答,看到别的地方提到“程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误”,这句话的意思是每个进程起来的时候文件描述符表里都会先有三个条目吗?它们指向的是什么呢。。。
        631810aa317a:@fasionchan 感谢回答!
        fasionchan:一般是从父进程继承,比如你在shell运行一个命令ps,那么ps进程0 1 2这三个文件描述符指向与shell一样;如果发生了重定向,如:ps > /dev/null ,那么,这是1指向 /dev/null
      • 曹真:目前简书关于底层的一些文章还很少,写出去之后反响也不怎么样。http://www.jianshu.com/p/a2dc2907ec28共勉 这里引用了你的文章 感谢!
        fasionchan:是的,关注底层的人越来越少
      • sugaryaruan:示意图太赞了
        fasionchan:@sugaryaruan 哈哈 喜欢就好

      本文标题:Linux文件描述符

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