阅读 140

文件描述符与位图

文件描述符的本质

文件描述符本质上是内核向进程提供的一种凭据,内核为进程维护了一张文件描述符表用来记录文件描述符和文件的对应关系,并且记录了读写模式相关的信息。

在Linux中,当每个进程被启动的时候,内核都会为其在/proc目录下创建一个虚拟目录,目录名称为进程的PID。在该目录下有一个名为fd的文件夹,记录了进程打开的文件。

首先我们启动一个Python解释器

image.png

然后执行ps -ef | grep python3查出Python解释器进程的PID是7072, 最后进入到 /proc/7072/fd image.png

可以看到,该目录中由三个文件, 这代表着进程已经打开三个文件, 文件描述符分别是0,1,2, 这些文件是操作系统都为进程分配三个文件描述符, 分别是:

  • 标准输入, fd=0。

  • 标准输出, fd=1。

  • 标准错误输出, fd=2。

执行一下ls -l可以看到,这三个文件都链接到了/dev/pts/0设备上,该设备代表了用户的SSH终端.

本文测试过程中均使用SSH连接到服务器上进行测试

image.png

既然是文件,意味着我们可以像操作文件一样操作它们。(这也是Linux的有趣之处)

我们标准输入文件写入数据print('Hello from kovogo'),再切换到另外一个窗口看一下

image.png

可以看到,另一窗口检查到了我们的输入. image.png

从以上,我们可以观察到文件描述符从0开始计数, 并且逐个增长,借助这个规律一些功能可以被巧妙的实现,当然也可以回答一些疑问,但是在这之前还是让我们先验证一下这个机制。

我们先创建三个文件,然后再按顺序打开它们
image.png image.png

根据此前的推测 1.log的文件描述符应该是3, 2.log的文件描述符应该4, 3.log的文件描述符应该是5,进入该进程的文件描述符目录,观察可以看到

image.png

select是怎么实现的? 为什么能监文件描述符的数量比epoll少?

经过上文的分析,我们已经知道文件描述符从0开始递增,并且不间断,select系统调用就利用了这个机制,其通过一个位图来存储要监控的文件描述符。那么什么是位图呢?

我们知道一个字节有8个位组成,当我们对这些比特位赋予了一定信息之后他就成了位图, 位图通常用于判断一个元素是否在集合中。

假设,给定一个只包含0至15的数组,我们需要对该数组进行去重,仅输出不重复的元素,那么除了使用Map来保存出现过的元素,我们还可以使用位图来处理。

如下所示,以下是一个2个字节的位图。 image.png

假设要判断一个元素是否在位图中,我们只需要:

  • 如果你使用short进行存储位图

bool exists = ((1 << elem) & bitmap) > 0 复制代码

  • 如果你使用byte进行存储位图

首先,要定位该元素可能会被存储在哪个字节, 直接对8进行整除即可, 然后定位该元素位于哪个比特位

int byte_pos = elem / 8; int elem_pos = elem % 8; bool exists = (1 << elem_pos) & bitmap[byte_pos]) > 0 复制代码

简单了解过位图之后,你就知道为啥select只能监控有限数量的描述符了,因为select存储文件描述符的位图是的大小是有限制,并且由于文件描述符是递增的所以该位图基本上不会有大量的比特位被浪费掉,但是,其位图大小是有限制。

我们简单调用一下sizeof看一下位图的大小, select.h中该位图的结构体类型名为fd_set. image.png

image.png

结合上图可以知道, 我的机子上可以最大监控8 * 128 = 1024个文件描述符,最大能监控的文件描述符值是1024,当然你可以通过编译内核来调整fd_set的大小。


作者:kovogo
链接:https://juejin.cn/post/7026361343011733534


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐