【问题标题】:select() on half-open socket does not return on close()?半开套接字上的 select() 不会在 close() 上返回?
【发布时间】:2016-02-23 09:41:46
【问题描述】:

我在阻塞套接字上执行select(),没有超时select(sock+1, &rfd, NULL, NULL, NULL)

这发生在一个目标是分派传入数据的线程中。另一个监视线程正在管理与对等方的保持活动状态,当它检测到死连接时,它将关闭套接字。

我期待select() 在这种情况下返回-1。它在 Windows 上执行此操作,但在 Linux 上从不执行此操作,因此当对等方非正常消失时,调度线程将永远锁定。为了完整起见,有待传输的数据,我尝试使用SO_LINGER,但这并没有改变任何东西。

问题可以通过在select() 中设置超时来解决,在这种情况下,在关闭和超时后,select() 最终会以-1 退出,但我认为,阅读文档时,select() 没有超时即使对等方没有响应,仍会在关闭时退出。

我是误用了select() 还是有更好的方法来处理半开套接字?

【问题讨论】:

    标签: linux sockets select


    【解决方案1】:

    是的,您滥用了selectman select 声明:

    如果 select() 监视的文件描述符在另一个线程中关闭,则结果未指定。在某些 UNIX 系统上,select() 解除阻塞并返回,并指示文件描述符已准备好(后续 I/O 操作可能会失败并出现错误,除非在 select() 返回和已执行 I/O 操作)。在 Linux(和其他一些系统)上,关闭另一个线程中的文件描述符对 select() 没有影响。总之,在这种情况下依赖于特定行为的任何应用程序都必须被视为有缺陷。

    所以你不能关闭来自其他线程的连接。不幸的是,poll 也有同样的问题。


    编辑

    有几种可能的解决方案,我没有关于您的应用程序的足够信息。可以考虑以下更改:

    • 如果您使用的是 linux,请使用 epoll 而不是 select,如果您使用的是其他操作系统,请使用其他现代轮询机制。 select 是一个相当老的函数,它是在没有认真考虑线程的时候设计的。
    • 在选择线程和保持活动线程之间建立通信通道。当保持活动线程检测到死节点时,不要关闭套接字本身,而是指示选择线程执行此操作。通常可以通过本地套接字完成。本地套接字被添加到选择描述符集,当保持活动线程向其写入内容时,选择线程唤醒并可以采取行动。

    【讨论】:

    • 谢谢!像往常一样,我应该有更好的 RTFM ... 话虽如此,您如何使用没有超时的 select() 并处理对等方变暗时发生的问题?
    • 我的应用程序必须在 Windows、OSX 和 Linux 上运行,所以仅 epoll 将不起作用(我当然可以 #ifdef 各种选项)但添加本地套接字并在其上选择将起作用。谢谢!
    猜你喜欢
    • 2021-08-19
    • 2013-02-23
    • 2010-10-09
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    相关资源
    最近更新 更多