【发布时间】:2014-08-23 17:04:26
【问题描述】:
我不太明白 select 函数中第一个参数的用途。 Wikipedia 将其描述为所有集合中的最大文件描述符,加上 1 。为什么 +1 以及为什么 select 需要这些信息?
【问题讨论】:
-
也许它需要抵消它,因为它认为有效的文件描述符编号来自
1 to n,而不是0 to (n - 1)。
我不太明白 select 函数中第一个参数的用途。 Wikipedia 将其描述为所有集合中的最大文件描述符,加上 1 。为什么 +1 以及为什么 select 需要这些信息?
【问题讨论】:
1 to n,而不是0 to (n - 1)。
在大多数 UNIX 内核 ABI 中,select 的 fd_set * 参数实际上是 unsigned * 或 unsigned long *,它们指向包含位的字数组。 select 的第一个参数告诉内核这些数组有多大以及应该检查多少位。
每个字包含 16 或 18 或 32 或 36 或 64 位(取决于机器的字长);内核将从用户空间读取nfds/wordsize 字,使用最后一个字(以及其他字的所有位)的nfds%wordsize 低位。
fd_set 数据结构和相关函数由 POSIX 引入,以便轻松管理这些位集,这些位集也可以移植到使用其他表示和内核 ABI 级别的其他系统。
【讨论】:
这是(原始)Berkeley 套接字实现的偶然细节。基本上,该实现使用文件描述符的 number 作为一些临时内部位数组的大小变量。由于 Unix 描述符从零开始,因此最大的描述符将比具有每个描述符一个插槽语义的任何数组的 size 小一。因此,“最大加一”的要求。这个加一调整本可以被系统调用本身吸收,但没有。
古代历史,仅此而已。结果是第一个参数的正确解释与描述符 values 的关系较少,而与它们的 number 关系(即要测试的描述符的最大数量)。参见Stevens et al 的第 6.3 节(这是 Rich Stevens 经典文本的修订和更新版本。如果你没有,那就去吧!)
【讨论】:
在 *Nix 系统中,文件描述符只是系统表的索引,fd_set 结构包含对应于这些索引的位掩码。当描述符被添加到fd_set 时,相应的位被启用。 select() 需要知道最高的描述符值,以便它可以循环遍历这些位并知道要停在哪一个。
在 Windows 上,套接字由内核对象的句柄表示,而不是由索引表示。 fd_set 结构包含一个套接字句柄数组和数组中套接字数的计数器。这样,select() 就可以循环遍历数组,这就是为什么 select() 的第一个参数在 Windows 上会被忽略。
【讨论】:
fd_set做成链表呢?
想法是select函数可以使用第一个参数来优化读取fd_set的时序。
在手册中:
man select
上面写着:
nfds 是三组中编号最高的文件描述符,加上 1。
所以select函数只检查fd_set中小于这个的fds,而不是fd_set中所有可能的fds。此大小在 FD_SETSIZE 常量中定义。
【讨论】:
fd_set 可以有多个值。如果select()“只检查fd_set中小于这个的fds,而不是fd_set中所有可能的fds”,它会跳过值。
nfd 是什么。不过,请查看您的答案的措辞:“select 函数仅检查 fd_set 中小于此的 fds,而不是 fd_set 中所有可能的 fds”。这意味着可以跳过添加到 fd_set 的值。只需修改您的措辞,以更清楚地说明select() 不会检查所有可能的 fd,只是实际添加到 fd_set 中的 fd。