使用 select() 时,文件描述符为 "set" 是什么意思?

When using select(), what does it mean for a file descriptor to be "set"?

使用select()时,我理解的过程是:

  1. 用您希望在数据进入时知道的文件描述符填充 fd_set 结构。
  2. 用您想知道何时可以写入的文件描述符填充 fd_set 结构。
  3. 调用 select() 并阻塞直到有事情发生。
  4. 一旦 select() returns,对所有文件描述符调用 ISSET() 以查看它们是否发生了问题,并相应地为它们提供服务。
  5. 重复。

然而,我不明白的是“设置”文件描述符的确切含义。在这个 documentation 中,它表示文件描述符是指定 fd_set 的一部分。但是,如果 ISSET() 检查文件描述符是否发生了某些事情,为什么要在每次迭代开始时甚至调用 select() 之前“设置”每个文件描述符?难道它们不应该只在发生变化时被“设置”吗?它们可以在 select() returns 之前的某个时候“取消设置”吗?

为您希望内核查看的文件句柄设置用于读取、写入和异常的 select 位。

内核将遍历位直到您在 select 的第一个参数中提供的限制。它会用 select.

的结果覆盖您发送的位

select return它设置的位数,这很重要,因为内核不需要检查所有的句柄,它可能 return 只检查一个,如果你有很多文件句柄,你应该使用 epoll,但无论如何,你可以计算找到的位数,直到它匹配 select return 并避免执行整个位掩码。

(尽管我认为大多数当前的 Unixish 内核会扫描所有位,因为存在 low-numbered 文件句柄可能会通过始终报告就绪而使高数字挨饿的错误。)

您可以根据需要将位掩码设置为发送到 select。如果您希望从套接字读取,请设置其读取位。如果您有数据等待写入套接字,请设置写入位。等等

您可能希望始终设置读取位,因为这是您判断套接字已关闭的方式,或者您可以尝试写入已关闭的套接字并收到 EPIPE 错误。

假设内核将缓冲您对套接字所做的所有写入是一个重大错误,这就是 select 有一个写入位的原因:它会在有缓冲区时触发 space 写入更多的数据,大概至少一页4K字节。