C++ winsock2是线程安全的吗?

C++ winsock2是线程安全的吗?,c++,multithreading,winsock2,C++,Multithreading,Winsock2,我正在编写一个小的3台服务器和1台客户端程序。两台服务器发送tcp消息,最后一台服务器使用winsock2发送upd数据报 我想知道是否可以通过使用线程(OpenMP或boost::threads)使两个线程同时从同一端口上的同一套接字侦听,从而实现同步recvfrom() 我正在windows7上使用VC++2010 感谢您的帮助。Winsock只允许对套接字进行一次阻塞IO调用。来自不同线程的多个阻塞调用将以“WSAEINPROGRESS”错误结束 如果您想发出并发IO请求,可以尝试使用异步

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

我想知道是否可以通过使用线程(OpenMP或boost::threads)使两个线程同时从同一端口上的同一套接字侦听,从而实现同步recvfrom()

我正在windows7上使用VC++2010


感谢您的帮助。

Winsock只允许对套接字进行一次阻塞IO调用。来自不同线程的多个阻塞调用将以“WSAEINPROGRESS”错误结束


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

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

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

但是,如果您使用的是UDP,并且协议是无状态的,那么这通常不需要担心

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

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

WSAEINPROGRESS
的描述进一步说明:

行动正在进行中

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

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

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

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

但除了这些警告,你应该没事

更新:要添加一些外部引用,请执行以下操作:
而且

不,套接字不是线程安全的,每个线程都需要一个套接字,但是,使用windows消息循环,可以通知一个线程与另一个线程,反之亦然,线程本身可以有消息循环;TCP是一种ByTestStream协议。如果一条消息一半被一个线程接收,一半被另一个线程接收,您将如何处理该消息?事实上,这是不可能的保护您对更基本的设计错误。在一个线程中接收并重新组装消息(无论如何这并不昂贵),然后将整个消息发送给其他线程进行进一步处理。感谢您的回复。我将考虑使用每个线程的一个套接字。对于TCP来说,一个注释通常对于同一个套接字同时调用ReCV是没有意义的,但是对于UDP来说它是完全好的。@ EZAKERM——在同一个线程上的两个阻塞调用是一个罕见的条件(想想,当一个线程已经被粘在ReCV上时,人们怎么可能从一个线程发出ReV?)MS文档表示,结果将是未定义的行为,而不是在其他情况下返回WSAEINPROGRESS的定义良好的行为。我真的很想知道它是如何为您工作的。我非常怀疑-文档中说的“每个任务或线程都有一个阻塞操作”。WSARecv的描述进一步指出,“在中断同一线程上正在进行的阻塞Winsock调用的APC内发出另一个阻塞Winsock调用将导致未定义的行为,Winsock客户端决不能尝试。”文档中讨论了APC“异步过程调用”的情况将在发出阻塞调用的同一线程上运行。由于APC将在线程恢复之前执行—用户模式APC确实有机会运行—并且如果它发出另一个阻塞套接字调用,则行为未定义。为了给出代码透视图,文档讨论的是在同一线程上运行的一些代码,其中recv或WSARecv仍在执行,这只有在有未完成的APC排队到该线程时才可能。是的,重点是,多个阻塞调用只是同一线程上的一个问题。但是当使用多个线程时就不行了(每个线程一个阻塞调用就可以了)。感谢您提供所有这些清晰的信息。因此,可以在UDP的两个线程中的同一套接字上运行两个wsarecv。因此,只有在调用线程中的两个阻塞操作而不是整个进程时,才会出现WSAEINPROGRESS错误。这是一个好消息,因为我在每个线程中都有一个recv()。先生,还有一个问题。如果我有两个UDP源,我可以使用一个线程和一个套接字(假设我使用相同的端口)从这些源接收数据吗?对于UDP,您通常会使用recvfrom获取数据以及对等方的地址和端口号,这样您就可以将回复发送回请求的来源地。由于没有任何连接,所以无论每个数据包来自同一个发送者还是不同的发送者都没有关系。