我正在尝试修复调用select()
的事件循环中的错误。当select()
返回EBADF时,会记录错误,然后重新初始化fd set并再次调用select。这导致无限的硬编码循环,在几秒钟内生成千兆字节的日志。
如果我的程序连接的其中一个tcp服务器执行了不干净的断开连接(例如,它是段错误),则会发生此错误。在这种情况下,我理想地希望我的程序删除该fd并继续运行(如果不可行则关闭)。
我的问题是,select()是否应该返回EBADF,或者这表明我的程序是错误的?即我应该在EBADF上断言失败,否则,我应该如何处理它?我是否会遍历fd集以找到" bad"文件描述符?
答案 0 :(得分:4)
您的代码中存在错误。修理它。您正在关闭套接字而不将其从选择器使用的FD集中移除。或者你刚刚编造了一个不是FD的FD并且正在FD集中使用它。
与此处的其他声明相反,网络问题不会导致此错误。网络中断不会关闭套接字,这是它们变为无效的唯一方法。只有关闭它们就可以了。连接不起作用的套接字如果继续写入,最终会导致ECONNRESET。对等体已断开连接的套接字将变为可读,其上的recv()
将返回零。
答案 1 :(得分:3)
如果在其中一个无效的fd_set中传入描述符,我的问题是,select()是否应该返回EBADF,或者这表明我的程序是错误的?
select()将返回EBADF。你不应该这样做,它表示你的程序中有一个错误 - 也许你在某个地方关闭文件描述符,但没有从fd_set中删除它。
答案 2 :(得分:2)
是的,我认为assert()
是个好主意。
来自select(2)
手册页:
EBADF 其中一个集合中提供了无效的文件描述符。 (也许是已经关闭的文件描述符,或者是一个文件描述符 哪个错误发生了。)
这意味着您已经传递了一个实际上与有效打开文件不匹配的文件描述符。
不导致fd使select
EBADF
失败的情景示例:
recv
返回0)。查看Linux内核源代码,如果确定您的集合中传递的其中一个fds与流程中的打开文件不对应,我们会看到select
可以返回EBADF
。这已在fs/select.c
max_select_fd
中进行了检查
在检查之后,do_select
只会返回有趣的" FDS。基础文件的file_operations.poll
函数甚至无法使do_select
返回任何不同的内容。
现在看起来完全不可能select
将为任何场景返回EBADF
,除了通过fd的编程要么关闭,要么永不开放。