Unix/Linux编程:文件描述符与打开文件之间的关系

一般人很可能会认为,文件描述符与打开的文件是一一对应关系。实际上并非如此。多个文件描述符指向同一打开文件,这极有可能,也属必要。这些文件描述符可以在相同或者不同的进程中打开。这些文件描述符可以在相同或者不同的进程中打开。

要理解具体情况如何,需要查看由内核维护的三个数据结构:

  • 进程级的文件描述符表
  • 系统级的打开文件表
  • 文件系统的i-node表

针对每个进程,内核为其维护打开文件的描述符(open file descriptor)表。该表的每一条目都记录了单个文件描述符的相关信息。如下所示。

  • 控制文件描述符操作的一组标志(目前,此类标志仅定义了一个-----close-on-exec标志)
  • 对打开的文件句柄的引用

内核对所有打开的文件维护有一个系统级的描述表格(open file sescriptor table)。有时,也叫做打开文件表(open file table),并将表中各条目称为打开文件句柄(open file handle)。一个打开文件句柄存储了与一个打开文件相关的全部信息,如下所示。

  • 当前文件偏移量(针对read()和write()时更新,或使用lseek()直接修改)
  • 打开文件时所使用的状态标志志(即,open()的 flags 参数)
  • 文件访问模式(如调用 open()时所设置的只读模式、只写模式或读写模式)
  • 与信号驱动 I/O 相关的设置
  • 对该文件 i-node 对象的引用

每个文件系统都会为驻留其上的所有文件建立一个 i-node 表。每个文件的i-node信息如下:

  • 文件类型(例如,常规文件、套接字或 FIFO)和访问权限
  • 一个指针,指向该文件所持有的锁的列表。
  • 文件的各种属性,包括文件大小以及与不同类型操作相关的时间戳

此处忽略了i-node在磁盘和内存中的表示差异。磁盘上的i-node记录了文件的固有属性,比如文件类型、访问权限和时间戳。访问一个文件时,会在内存上为i-node场景一个副本,其中记录了引用该i-node的打开文件句柄数量以及该i-node所在设备的主-从设备号,还包括一些打开文件时与文件相关的临时属性。例如:文件锁。

下图展示了文件描述符、打开的文件句柄以及 i-node 之间的关系:
在这里插入图片描述

  • 在进程 A 中,文件描述符 1 和 20 都指向同一个打开的文件句柄(标号为 23)。这可能是通过调用 dup()、dup2()或 fcntl()而形成的
  • 进程A的文件描述符2和进程B的文件描述符2都指向同一个打开的文件句柄(标号为73)。这种情形可能在调用 fork()后出现(即,进程 A 与进程 B 之间是父子关系),或者当某进程通过UNIX 域套接字将一个打开的文件描述符传递给另一进程时,也会发生
  • 此外,进程 A 的描述符 0 和进程 B 的描述符 3 分别指向不同的打开文件句柄,但这些句柄均指向 i-node 表中的相同条目(1976),换言之,指向同一文件。发生这种情况是因为每个进程各自对同一文件发起了 open()调用。同一个进程两次打开同一文件,也会发生类似情况

上述讨论揭示出如下要点。

  • 两个不同的文件描述符,若指向同一打开文件句柄,将共享同一文件偏移量。因此,
    如果通过其中一个文件描述符来修改文件偏移量(由调用 read()、write()或 lseek()
    所致),那么从另一文件描述符中也会观察到这一变化。无论这两个文件描述符分属
    于不同进程,还是同属于一个进程,情况都是如此
  • 要获取和修改打开的文件标志(例如,O_APPEND、O_NONBLOCK 和 O_ASYNC),可执行 fcntl()的 F_GETFL 和 F_SETFL 操作,其对作用域的约束与上一条颇为类似。
  • 相形之下,文件描述符标志(亦即,close-on-exec 标志)为进程和文件描述符所私有。对这一标志的修改将不会影响同一进程或不同进程中的其他文件描述符。

文件描述符 VS 文件描述

  • 文件描述表示的是一个打开文件的上下文信息息(大小、内容、编码等与文件有关的信息),可以比喻为一个抽屉,这部分内容实际上是由内核来管理的。
  • 而用户空间的应用程序如果要操作文件怎么办。就是通过 open()这样的系统调用向内核请求,然后内核分配给用户空间一个文件描述符(file descriptor)。
  • 这个文件描述符可以比喻为抽屉的把手(handle之所以翻译为“句柄”,这就是原因),有了这个把手(文件描述符),用户就可以操作抽屉(文件描述)里的内容了。
  • 但是,一个抽屉可以有多个把手(即文件描述可以对应多个文件描述符),只有当所有的把手(文件描述符)都关闭了,内核就知道此时没有用户空间的程序要用这个抽屉了(文件描述),那么就把它回收。

文件描述实际上是内核中的一个数据结构,而用户空间中的文件描述符不过是一个整数,epoll的兴趣列表实际关注的是内核中的数据结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值