我试图修复一个调用select()
的事件循环中的错误。当select()
返回EBADF时,会记录一个错误,然后重新初始化fd集并再次调用select。这会导致日志记录的无限硬循环,在几秒钟内生成千兆字节的日志。
如果我的程序连接到的tcp服务器之一不干净地断开连接(例如segfaults),就会发生此错误。在这种情况下,我希望我的程序删除该fd并继续运行(或关闭,如果这是不可行的)。
我的问题是,select()是否应该返回EBADF,或者这是否表明我的程序有错误?也就是说,我应该在EBADF上Assertfail,否则,我应该如何处理它?我会循环遍历fd集来找到“坏”的文件描述符吗?
3条答案
按热度按时间6xfqseft1#
你的代码中有一个bug。修复它。在某些地方,你关闭了一个套接字,而没有将它从选择器使用的FD集中删除。或者,你刚刚创建了一个不是FD的FD,并在FD集合中使用它。
与此处的其他陈述相反,网络问题不会导致此错误。网络中断不会关闭套接字,这是套接字失效的唯一途径。只有关闭它们才能做到。如果你继续向一个套接字写入数据,它的连接不起作用,最终会导致一个错误。对等体断开连接的套接字将变得可读,其上的
recv()
将返回零。svmlkihl2#
我的问题是,select()是否应该返回EBADF,或者这是否表明我的程序有错误?
select()返回EBADF,如果你在一个fd_set中传入一个无效的描述符。你不应该这样做,这表明你的程序中有一个错误-也许你已经接近了(在某个地方删除了一个文件描述符,但没有从fd_set中删除它)。
scyqe7ek3#
是的,我认为这将是一个好主意
assert()
。从
select(2)
手册页:EBADF在其中一个集合中提供了无效的文件描述符。(可能是已经关闭的文件描述符,或者是发生错误的文件描述符。)
这意味着您传递的文件描述符实际上与有效的打开文件不匹配。
以下场景的示例 * 不会 * 导致fd通过
EBADF
使select
失败:recv
返回0)。查看Linux内核源代码,我们可以看到,如果确定传递到集合中的某个fds与进程中打开的文件不对应,
select
可以返回EBADF
。这在fs/select.c
中的max_select_fd
中检查在检查之后,
do_select
将只返回“感兴趣的”fd的计数。底层文件的file_operations.poll
函数甚至不能使do_select
返回任何不同的值。现在看起来
select
在任何情况下都不可能返回EBADF
,除了程序传递一个关闭或从未打开的fd。