【问题标题】:is winsock2 thread safe?winsock2线程安全吗?
【发布时间】:2012-12-21 02:15:04
【问题描述】:

我正在编写一个小型的 3 个服务器和 1 个客户端程序。 2台服务器发送tcp消息,最后一台使用winsock2发送upd数据报。

我想知道我是否可以通过使用线程(OpenMP 或 boost::threads)来模拟 recvfrom(),以便 2 个线程同时从同一个端口上的同一个套接字进行侦听。

我在 windows7 上使用 VC++ 2010。

感谢您的帮助。

【问题讨论】:

  • 不,套接字不是线程安全的,每个线程都需要一个套接字,但是,使用 Windows 消息循环,您可以通知一个线程,反之亦然,线程本身可以有消息循环.
  • “TCP 消息”可以分片; TCP 是一种字节流协议。您将如何处理一个线程接收一半、另一个线程接收一半的消息?不可能的事实可以保护您免受更基本的设计错误的影响。在一个线程中接收和重组消息(这并不昂贵),然后将整个消息分派给其他线程进行进一步处理。
  • 感谢您的回复。我会考虑每个线程使用一个套接字。
  • 请注意,对于 TCP,为同一个套接字同时调用 recv 通常是没有意义的,但对于 UDP 则完全没问题。
  • @ezzakrem - 同一线程上的两个阻塞调用是一种罕见的情况(想想当线程已经卡在 recv 上时,通常如何从线程发出 recv),MS 文档说明了结果将是未定义的行为,而不是在其他情况下返回 WSAEINPROGRESS 的明确定义的行为。我真的很想知道它是如何为您工作的。

标签: c++ multithreading winsock2


【解决方案1】:

是的,套接字是线程安全的,但是你必须小心。一种常见的模式(当使用阻塞 IO 时)是让一个线程在一个套接字上接收数据,而另一个线程在同一个套接字上发送数据。让多个线程从一个套接字接收数据对于 UDP 套接字通常很好,但在大多数情况下对 TCP 套接字没有多大意义。 WSARecv 的文档中有警告:

不应同时在同一个套接字上调用 WSARecv 不同的线程,因为它可能导致不可预知的缓冲区 顺序。

但是,如果您使用的是 UDP 并且协议是无状态的,这通常没有任何问题。

还要注意WSAEINPROGRESS错误码主要适用于Winsock 1.1:

WSAEINPROGRESS:阻塞的 Windows Sockets 1.1 调用正在进行中,或者服务提供者仍在处理回调函数。

WSAEINPROGRESS的描述进一步说明:

操作正在进行中。

当前正在执行阻塞操作。 Windows 套接字仅允许单个阻塞操作(每个任务或线程)处于未完成状态,并且如果进行了任何其他函数调用(无论它是否引用该套接字或任何其他套接字),该函数都会失败并出现 WSAEINPROGRESS 错误。

请注意,这里讨论的是每个任务或线程的单个阻塞操作。

此外,WSARecv 的文档中还有一个附加警告:

在 APC 内发出另一个阻塞 Winsock 调用,中断同一线程上正在进行的阻塞 Winsock 调用将导致未定义的行为,并且 Winsock 客户端绝不能尝试。

但除了那些警告之外,你应该没问题。

更新:添加一些外部引用: alt.winsock.programming: Is socket thread-safe?Winsock Programmer’s FAQ: Is Winsock thread-safe?

【讨论】:

  • 感谢您提供所有这些清晰的信息。因此,可以在 UDP 的两个线程中在同一个套接字上运行两个 wsarecv。所以只有当我在线程中调用两个阻塞操作而不是整个进程时,我才会得到 WSAEINPROGRESS 错误。这是一个好消息,因为我在每个线程中都有一个 recv()。另一个问题,先生。如果我有两个 UDP 源,我可以使用一个线程和一个套接字从这些源接收数据吗(假设我使用相同的端口)?
  • 对于 UDP,您通常会使用 recvfrom 来获取数据以及对等方的地址和端口号,因此您可以将回复发送回请求的来源。由于无论如何都没有连接,因此每个数据包来自同一发送者或不同发送者都没有关系。
【解决方案2】:

Winsock 只允许一个套接字上的阻塞 IO 调用。来自不同线程的多个阻塞调用最终会出现“WSAEINPROGRESS”错误。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668%28v=vs.85%29.aspx#WSAEINPROGRESS.

如果您想发出并发 IO 请求,您可以尝试使用异步 IO 或重叠 IO(用 Windows 的说法)。但我想你会想要并发处理数据而不是并发读取数据。在这种情况下,您可以让一个线程发出 IO 请求,其他线程进行处理。

【讨论】:

  • 我非常怀疑 - 文档声明“单个阻塞操作 - 每个任务或线程”。 WSARecv 的描述进一步指出“在 APC 内发出另一个阻塞 Winsock 调用,中断同一线程上正在进行的阻塞 Winsock 调用将导致未定义的行为,并且 Winsock 客户端绝不能尝试。”
  • 文档正在讨论 APC“异步过程调用”将在发出阻塞调用的同一线程上运行的情况。由于 APC 将在线程恢复之前立即执行 - 用户模式 ​​APC 确实有机会运行 - 如果它发出另一个阻塞套接字调用,则行为未定义。从代码的角度来看,文档正在讨论在 recv 或 WSARecv 仍在执行的同一线程上运行的一些代码,这只有在线程中有未完成的 APC 排队时才有可能。
  • 是的,关键是不止一个阻塞调用只是同一个线程的问题。但在使用多个线程时不是(每个线程一个阻塞调用就可以了)。
猜你喜欢
  • 1970-01-01
  • 2020-04-15
  • 2011-07-04
  • 2014-04-26
  • 2012-11-30
  • 2010-12-30
  • 2013-03-12
  • 2021-08-03
  • 2010-12-27
相关资源
最近更新 更多