socket select()是如何工作的?

14

如网络编程书籍所述,select() 用于监视一组文件描述符以进行读取操作。例如,以下是部分代码:

select(numfds, &read_fds, NULL, NULL, NULL);

这里的numfds是read_fds中套接字数量的最大值+1。这是否意味着每个“监视循环”select()都会从0到numfds检查进程的所有文件描述符?我的意思是,如果我只有两个要监视的文件描述符(0和26),那么select是否会监视从0到26的所有描述符?

2个回答

9

select函数根据你传递的文件描述符集合(readfdswritefdsexceptfds)来选择要监视的文件描述符。这些集合通常被实现为位向量,因此select将扫描该向量以查看哪些文件描述符已被选中。为了优化效率,您需要传递要扫描的文件描述符数量,以便select不必查看所有文件描述符,而只需查看前面的指定数量。

由于扫描和每次调用select后重置文件描述符集,该函数调用相当昂贵。在许多平台上,select仅在poll系统调用之上实现,后者提供了更有效的文件描述符等待接口。


是的,但它是否扫描了从0到numfds的所有套接字? - Tural Gurbanov
为什么增加一个的责任在调用者身上? - dreamlax
@dreamlax,和C字符串以\0结尾的原因一样,因为有人这么说,并且从那时起就一直是这样。 - Jesus Ramos
3
是的,它将扫描从“0”到“numfds”的所有内容。如果想避免这种情况,请使用“poll”(额外好处:poll不会修改输入数组,所以您不必在每个循环中重新添加fds)。 - nneonneo
因为我们从0开始计数。所以如果我们最高的套接字fd等于26,这意味着我们应该监视从0到26的描述符,这相当于“highest_socket + 1”。 - Tural Gurbanov

6
每个监视周期意味着操作系统在某种程度上进行周期性描述符检查,可以通过事件或中断来处理它。当套接字文件描述符收到数据时,描述符文件会被填充数据并通知等待它的进程。这不会立即发生,因为进程不会立即唤醒,只是重新放回到准备运行队列(因为它被select调用阻塞)。如果select调用失败(在超时内未收到数据),则计时器会触发并将进程放回运行队列。
是的,在FD_SET 0-26中检查或监视fd。这只是为了给文件描述符搜索设定一个上限。如果我没记错的话,这是因为内部实现了一个fd_set类型的位集,因为这样可以节省空间并更容易指定索引。由于我有一段时间没有访问glibc代码,所以我之前的声明可能是错误的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接