如何中止winsock阻塞调用?

问题描述 投票:0回答:3

我在 C++ 中使用 Winsock 2,并且想知道如何使我的服务器停止从客户端连接读取。读取线程被

recv()
阻塞,我不知道如何中止它。一种方法是使用带有
select()
的非阻塞套接字,但该线程必须等待才能检查新的
select()

停止读取套接字的正确方法是什么?

c++ winsock blocking
3个回答
2
投票

要中止对

recv()
的阻塞调用,您可以使用
closesocket()
another 线程关闭套接字。即使有点难看,也应该有用。

您也可以尝试

shutdown()
插座(我从未测试过)。


1
投票

如果你的程序除了处理套接字 I/O 之外还有其他事情要做,你就不应该首先阻塞。

您声称您的线程必须等待,但这只是程序当前设计的反映。您应该重新设计它,以便它可以与某种形式的非阻塞套接字一起使用。每个网络问题都可以使用非阻塞套接字来解决。

由于您使用的是 Winsock,因此您在这里有 许多替代方案,而不仅仅是

select()
。仅当您的应用程序必须在许多平台上运行并且您无法使用每个现代平台上可用的高级(但相互不兼容)替代方案时,
select()
才是一个不错的选择。


0
投票

可以使用

select
accept
recv
,无需轮询或超时间隔。

无论您想要一个服务器还是只是一个客户端(或多个客户端),此解决方案都可以正常工作。这个答案假设您将有一个专用线程用于调用

accept
,并且每个连接的客户端都有一个线程。

  1. 创建一个套接字对(在 Windows 上,您需要创建一个本地主机服务器并将客户端连接到它,然后关闭侦听套接字)。将这两个套接字称为 SocketPairSend 和 SocketPairReceive。

  2. 对于 TCP 服务器,accept 线程将调用 select,将 2 个套接字传递到 readfds 参数:侦听套接字和 SocketPairReceive。

  3. 对于 TCP 客户端,您还可以调用

    select
    ,将 2 个套接字传递到
    readfds
    参数中:客户端套接字和 SocketPairReceive。

在我的测试代码中,我有

accept
线程、从
accept
接收的新客户端的线程,以及通过
connect
连接到服务器的其他客户端,所有这些都使用
select
调用,传递相同的额外 SocketPairReceive 套接字.

当您想要关闭服务器时,只需在 SocketPairSend 上发送一个字节,所有线程都会从其

select
调用中唤醒。

如果您已经有服务器,则可以避免使用套接字对。您可以连接一个虚拟客户端并使用它的套接字(从

accept
获得)作为您的
accept
和客户端线程传递到
select
。但我更喜欢套接字对方法,因为它适用于所有场景(即,当您没有 TCP 服务器时)。

谈谈我遇到的其他建议:

  • 使用
    closesocket
    似乎有效,但在其文档中明确指出,在另一个阻塞调用正在进行时不要这样做。它看起来也很老套。还有一个需要注意的赛车条件。
  • 使用
    shutdown
    仅在某些情况下有效。它永远不会用于中止
    accept
    。由于与 closesocket 相同的原因,它也有点狡猾。从插座系统脚下扫地毯可能会产生奇怪的结果。
  • 您可以通过连接客户端来中止
    accept
    - 简单且无害,但有点 hacky。
  • 在 Windows 上,您可以使用 WSARecv 和 WaitForMultipleObjects。我没试过。我在这个旧的 Google 网上论坛帖子这里看到了它。

在每个人都跳出来说我不应该使用阻塞套接字等之前,我想要一个简单的解决方案,对于我正在开发的一个简单项目,并感到有必要使用旧的

select
写一个对我有用的答案、
accept
recv
具有阻塞套接字和线程。希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.