如何中止winsock阻塞调用?

发布于 2024-08-18 16:12:16 字数 205 浏览 7 评论 0原文

我在 C++ 中使用 Winsock 2,并且想知道如何使我的服务器停止从客户端连接读取数据。读取线程在 recv() 中被阻塞,我不知道如何中止它。实现此目的的一种方法是使用带有 select() 的非阻塞套接字,但该线程必须在检查新的 select() 之前等待。

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

I use Winsock 2 in C++, and wonder how to make my server stop reading from the client connection. The reading thread gets blocked in recv() and I have no idea how to abort it. One way to do this is use non-blocking sockets with select(), but this thread has to wait before checking the new select().

What is the proper way to stop reading the socket?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-08-25 16:12:16

要中止对 recv() 的阻塞调用,您可以从另一个线程中使用 closesocket() 关闭套接字。即使它有点难看,它也应该有效。

您也可以尝试 shutdown() 套接字(我从未测试过)。

To abort the blocking call to recv(), you can close the socket with closesocket() from another thread. Even if it's a bit ugly, it should work.

You can try to shutdown() the socket too (I never tested that).

携余温的黄昏 2024-08-25 16:12:16

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

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

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

If your program has other things to do besides working with socket I/O, you should not block in the first place.

You claim your thread must wait, but that's just a reflection of your program's current design. You should redesign it so it works with some form of non-blocking sockets. Every networking problem can be addressed using non-blocking sockets.

Since you're using Winsock, you have many alternatives here, not just select(). select() is a good choice only if your application must run on many platforms and you are unable to use the superior (but mutually incompatible) alternatives available on every modern platform.

墨小墨 2024-08-25 16:12:16

可以使用 selectacceptrecv 而无需轮询或超时间隔。

无论您想要一个服务器还是只是一个客户端(或多个客户端),该解决方案都可以正常工作。这个答案假设您将有一个专用线程用于调用 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 服务器时)。 Socketpair 更好地支撑了这个概念 - 它充当一个您可以等待的事件,一个 select 可以接受的事件(Linux 在这方面更灵活,但在 Windows 上,select只能接受套接字)。

关于我遇到的其他建议的一句话:

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

在每个人都跳出来说我不应该使用阻塞套接字等之前,我想要一个简单的解决方案,对于我正在开发的一个简单项目,并感到有必要使用旧的 select 编写一个对我有用的答案acceptrecv 具有阻塞套接字和线程。希望这有帮助!

It's possible to use select, accept and recv without polling or timeout intervals.

Whether you want a server or just a client (or many clients), this solution will work all the same. This answer assumes you will have a dedicated thread for calling accept, and a thread per each client that connects in.

  1. Create a socketpair (on Windows, you would need to create a localhost server and connect a client to it, then close the listening socket). Call the two sockets SocketPairSend and SocketPairReceive.

  2. For your TCP server, the accept thread would call select, passing 2 sockets into the readfds parameter: the listening socket and SocketPairReceive.

  3. For TCP clients, you would also call select, passing 2 sockets into the readfds parameter: the client socket and SocketPairReceive.

In my test code, I have the accept thread, threads for new clients received from accept, and additional clients connected to the server via connect, all using the select call, passing the same extra SocketPairReceive socket.

When you want to shut the server down, simply send a byte on SocketPairSend, and all the threads would wake up from their select calls.

You could avoid using a socketpair if you already have a server. You can just connect a dummy client in and use its socket (that you got from accept) for your accept and client threads to pass into select. But I prefer the socketpair approach because it works for all scenarios (i.e., when you don't have a TCP server). Socketpair underpins the concept better - it acts as an event that you can wait on, one that select can accept (Linux is more flexible in this regard, but on Windows, select can only accept sockets).

A word on other suggestions that I've come across:

  • Using closesocket appears to work but it's explicitly stated in its documentation to not do this while another blocking call is in progress. It also seems hacky. There's also a racing condition to be aware of.
  • Using shutdown only works in some scenarios. It never works for aborting accept. It's also a little dodgy for the same reasons closesocket is. Sweeping the rug from under the socket system's feet may potentially create weird results.
  • You may abort an accept by connecting a client in - simple and harmless, but a little hacky. I needed a solution that worked for recv as well, so I ultimately ditched this.
  • On Windows, you can use WSARecv and WaitForMultipleObjects. I've not tried it. I saw it on this old Google Groups post here.

Before everyone jumps to say that I should not be using blocking sockets etc, well I wanted a simple solution, for a simple project I am working on and felt compelled to write an answer that worked for me, using the good old select, accept and recv with blocking sockets and threads. Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文