我不太了解select
函数中第一个参数的用途。 Wikipedia将其描述为所有集合中的最大文件描述符加1。为什么+1以及为什么select
需要此信息?
答案 0 :(得分:5)
在* Nix系统中,文件描述符只是系统表的索引,fd_set
结构包含与这些索引对应的位掩码。将描述符添加到fd_set
时,将启用相应的位。 select()
需要知道最高描述符值,以便它可以遍历这些位并知道要停在哪一位。
在Windows上,套接字由内核对象的句柄表示,而不是由索引表示。 fd_set
结构包含一个套接字句柄数组和一个数组中套接字数量的计数器。这样,select()
可以循环遍历数组,这就是为什么在Windows上忽略select()
的第一个参数的原因。
答案 1 :(得分:3)
这是(原始)伯克利套接字实现的偶然细节。基本上,该实现使用文件描述符的 number 作为一些临时内部位数组的大小调整变量。由于Unix描述符从零开始,因此最大描述符将比具有每个描述符一个插槽语义的任何数组的 size 小一个。因此,“最大加一”的要求。这个加1调整本来可以吸收到系统调用本身,但事实并非如此。
古代历史,就是这样。结果是第一个参数的正确解释与描述符值的关系不如它们的数(即要测试的最大描述符数)。参见Stevens et al的第6.3节(这是Rich Stevens经典文本的修订和更新版本。如果你没有它,那就去吧!)
答案 2 :(得分:1)
ideia是select函数可以使用第一个参数来优化读取fd_set的时序。
在手册中:
man select
它说:
nfds是三组中任何一组中编号最高的文件描述符,加上1。
因此select函数只检查fd_set中小于此值的fds,而不检查fd_set中所有可能的fds。此大小在FD_SETSIZE常量中定义。
答案 3 :(得分:1)
在大多数UNIX内核ABI中,fd_set *
的{{1}}参数实际上是select
或unsigned *
,指向包含位的字数组。 unsigned long *
的第一个参数告诉内核这些数组有多大以及应该检查多少位。
每个字包含16或18或32或36或64位(取决于机器的字大小);内核将使用最后一个单词中的select
个低位(以及其他单词的所有位)从用户空间读取nfds/wordsize
个单词。
POSIX引入了nfds%wordsize
数据结构和相关函数,可以轻松管理这些位集,这些位集也可以移植到使用其他表示和内核ABI级别的其他系统。