查询选择系统调用

select()定义为:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); 

nfds表示所有给定集合中的最高文件描述符加1。 我想知道为什么fd_set信息可用时select()需要这些数据。

如果集合中的FD4,8,9,那么nfds的值将是10. select()moniter fds 9,8,7,6,5,4?

问题在于,fd_set并不像你想象的那样真正的“集合”。 幕后细节是fd_set的实现只是一个用作位域的整数。 换句话说,执行

 fd_set foo; FD_CLEAR(&foo); FD_SET(&foo, 3); 

将foo设置为十进制值8 – 它将第四最不重要的位设置为1(记住0是有效的描述符)。

 FD_SET(&foo, 3); 

相当于

 foo |= (1 << 3); 

因此,为了使select正常工作,需要知道fd_set的哪些位是您关心的位。 否则,它将无法告知“在”集合中的“零”位,但是从“不在”集合中的零位设置为“假”。

在您的示例中,具有4,8和9集且n = 10的fd_set被解释为“具有10个条目的集合(fds 0-9)。条目4,8和9为真(监视它们)。条目1 ,2,3,5,6,7是假的(不监视它们)。任何大于9的fd值都不在设定的时间内。“

选择使用FD_SET宏监视已启用的FD。 如果未启用任何FD进行监视,则select()不会监视任何FD。

“nfds”绝对是多余的,但它是select()接口的一部分,所以你需要使用它:)

无论如何,如果你在集合中有{4,8,9},你将nfds设置为10(正如你所提到的),而select()将只监视三个FD 4,8和9。

它可能是一个优化,因此select不必遍历整个fd_set来找出实际使用的描述符。 如果没有该参数, select将始终需要查看整个集合以查找调用中实际使用的描述符,使用参数,可以省略其中一些工作。