我应该在select()EBADF上Assertfail吗?

htrmnn0y  于 2023-10-15  发布在  其他
关注(0)|答案(3)|浏览(84)

我试图修复一个调用select()的事件循环中的错误。当select()返回EBADF时,会记录一个错误,然后重新初始化fd集并再次调用select。这会导致日志记录的无限硬循环,在几秒钟内生成千兆字节的日志。
如果我的程序连接到的tcp服务器之一不干净地断开连接(例如segfaults),就会发生此错误。在这种情况下,我希望我的程序删除该fd并继续运行(或关闭,如果这是不可行的)。
我的问题是,select()是否应该返回EBADF,或者这是否表明我的程序有错误?也就是说,我应该在EBADF上Assertfail,否则,我应该如何处理它?我会循环遍历fd集来找到“坏”的文件描述符吗?

6xfqseft

6xfqseft1#

你的代码中有一个bug。修复它。在某些地方,你关闭了一个套接字,而没有将它从选择器使用的FD集中删除。或者,你刚刚创建了一个不是FD的FD,并在FD集合中使用它。
与此处的其他陈述相反,网络问题不会导致此错误。网络中断不会关闭套接字,这是套接字失效的唯一途径。只有关闭它们才能做到。如果你继续向一个套接字写入数据,它的连接不起作用,最终会导致一个错误。对等体断开连接的套接字将变得可读,其上的recv()将返回零。

svmlkihl

svmlkihl2#

我的问题是,select()是否应该返回EBADF,或者这是否表明我的程序有错误?
select()返回EBADF,如果你在一个fd_set中传入一个无效的描述符。你不应该这样做,这表明你的程序中有一个错误-也许你已经接近了(在某个地方删除了一个文件描述符,但没有从fd_set中删除它)。

scyqe7ek

scyqe7ek3#

是的,我认为这将是一个好主意assert()
select(2)手册页:

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

这意味着您传递的文件描述符实际上与有效的打开文件不匹配。
以下场景的示例 * 不会 * 导致fd通过EBADF使select失败:

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

查看Linux内核源代码,我们可以看到,如果确定传递到集合中的某个fds与进程中打开的文件不对应,select可以返回EBADF。这在fs/select.c中的max_select_fd中检查
在检查之后,do_select将只返回“感兴趣的”fd的计数。底层文件的file_operations.poll函数甚至不能使do_select返回任何不同的值。
现在看起来select在任何情况下都不可能返回EBADF,除了程序传递一个关闭或从未打开的fd。

相关问题