我应该在select()EBADF上断言失败吗?

时间:2015-01-18 23:07:51

标签: c sockets tcp

我正在尝试修复调用select()的事件循环中的错误。当select()返回EBADF时,会记录错误,然后重新初始化fd set并再次调用select。这导致无限的硬编码循环,在几秒钟内生成千兆字节的日志。

如果我的程序连接的其中一个tcp服务器执行了不干净的断开连接(例如,它是段错误),则会发生此错误。在这种情况下,我理想地希望我的程序删除该fd并继续运行(如果不可行则关闭)。

我的问题是,select()是否应该返回EBADF,或者这表明我的程序是错误的?即我应该在EBADF上断言失败,否则,我应该如何处理它?我是否会遍历fd集以找到" bad"文件描述符?

3 个答案:

答案 0 :(得分:4)

您的代码中存在错误。修理它。您正在关闭套接字而不将其从选择器使用的FD集中移除。或者你刚刚编造了一个不是FD的FD并且正在FD集中使用它。

与此处的其他声明相反,网络问题不会导致此错误。网络中断不会关闭套接字,这是它们变为无效的唯一方法。只有关闭它们就可以了。连接不起作用的套接字如果继续写入,最终会导致ECONNRESET。对等体已断开连接的套接字将变为可读,其上的recv()将返回零。

答案 1 :(得分:3)

  

我的问题是,select()是否应该返回EBADF,或者这表明我的程序是错误的?

如果在其中一个无效的fd_set中传入描述符,

select()将返回EBADF。你不应该这样做,它表示你的程序中有一个错误 - 也许你在某个地方关闭文件描述符,但没有从fd_set中删除它。

答案 2 :(得分:2)

是的,我认为assert()是个好主意。

来自select(2)手册页:

  

EBADF 其中一个集合中提供了无效的文件描述符。                 (也许是已经关闭的文件描述符,或者是一个文件描述符                 哪个错误发生了。)

这意味着您已经传递了一个实际上与有效打开文件不匹配的文件描述符。

导致fd使select EBADF失败的情景示例:

  • 关闭连接的远程套接字端点。 (recv返回0)。
  • 拔下网络连接,(甚至是USB设备)。

查看Linux内核源代码,如果确定您的集合中传递的其中一个fds与流程中的打开文件不对应,我们会看到select可以返回EBADF。这已在fs/select.c

中的max_select_fd中进行了检查

在检查之后,do_select只会返回有趣的" FDS。基础文件的file_operations.poll函数甚至无法使do_select返回任何不同的内容。

现在看起来完全不可能select将为任何场景返回EBADF,除了通过fd的编程要么关闭,要么永不开放。