【问题标题】:Unblock a Blocked Winsock accept() Call取消阻止被阻止的 Winsock accept() 调用
【发布时间】:2012-01-03 17:48:18
【问题描述】:

我在 VS 2008 下使用 Winsock。

我有一个线程专门用于通过对accept() 的阻塞调用来接受传入的TCP 连接请求。当我的应用程序需要关闭时,我需要以某种方式解除对该线程的阻塞,以便它可以执行关闭工作并退出。有什么方法可以解除对 accept() 的阻止吗?

我将发布另一个问题,以防无法解除对 accept() 的阻止。那个问题是:如果我硬杀掉在 accept() 上被阻塞的线程,会不会发生任何不好的事情(操作系统数据结构的损坏等)?

谢谢, 戴夫

【问题讨论】:

  • 你不能关闭你被阻塞的套接字吗?这将导致accept() 返回。
  • IME,在 accept() 被阻止的情况下退出应用程序就可以了。操作系统会清理干净,不会损坏任何东西。如果你真的,绝对必须明确清理,然后按照其他海报的建议从另一个线程关闭套接字。

标签: winsock


【解决方案1】:

解除阻塞accept() 的一种方法是关闭来自另一个线程的侦听套接字。否则,您可以将侦听套接字设置为非阻塞模式并使用select()(它确实支持超时)来检测何时可以无阻塞地调用accept()。

【讨论】:

  • 我相信这个解决方案很容易出现竞争。有一个线程在循环中但不在select() 的窗口中,检查select() 的返回值;第二个线程成功执行closesocket();第三个线程打开一个具有相同句柄值的新套接字;第一个线程继续在select() 中等待,但现在等待具有相同句柄值的不同套接字。
  • 如果您使用我提到的select() 方法,那么第二个线程不需要调用closesocket()。它可以简单地设置第一个线程寻找的信号,以便它可以尽早关闭自己的套接字。使用select() 确保第一个线程不会在accept() 中被无限期阻塞,只需在select() 说之前不调用accept()。
【解决方案2】:

解除对来自另一个线程的 accept() 调用的阻塞的可靠方法是使用 connect() 创建连接。当然,线程需要知道正在监听的 IP 地址和端口。

【讨论】:

    【解决方案3】:

    直截了当,针对 Windows,closesocket() 无错误返回并解除阻塞调用 accept() 的线程。

    对 select() 进行轮询并不是您真正想要的! 从其他线程连接并不是您真正想要的!

    例如对于 linux,close(socket) 不会解除对监听线程的阻塞, 但是 shutdown(socket, SHUT_RD) 会;另外socket需要关闭。

    【讨论】:

    • 非常感谢,shutdown(socket, SHUT_RD) 是唯一有效的方法。不幸的是,正确的回应没有投票:(
    • 问题其实是指windows。通常,当您创建包含套接字的平台抽象时,您会传递等效的问题。我也想知道,你发现答案只嵌套在非常选定的线程中。
    【解决方案4】:

    我过去使用的一种方法是为 accept() 提供超时值 - 当它超时时,你检查一个“取消”标志 - 如果设置,你停止 - 如果没有,你回到循环接受()调用。

    我认为杀死线程会起作用,但您应该小心确保它是您的线程,例如,不是 .NET 线程池线程。

    编辑: Remy 是对的,并且认为我什至做了一个快速的 google 来验证我记得的结构是否存在 - 似乎太快了。腮红等。

    如果你想保持阻塞语义,它会看到从另一个线程关闭套接字(或中止你的阻塞线程)将是要走的路。

    【讨论】:

    • accept() 在 WinSock 中没有自己的超时参数。您必须将侦听套接字置于非阻塞模式,然后使用select()(确实支持超时)来检测何时可以无阻塞地调用accept()。
    • 杀死线程要完整得多,这将涉及太多其他需要考虑的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 2020-10-27
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    相关资源
    最近更新 更多