在来自多个线程的阻塞套接字上使用 send()

Posted

技术标签:

【中文标题】在来自多个线程的阻塞套接字上使用 send()【英文标题】:Using send() on a blocking socket from multiple threads 【发布时间】:2015-02-25 23:26:43 【问题描述】:

我读到你不应该在来自多个线程的阻塞套接字上使用send(),但我不知道为什么!如果我想在多个线程中使用send(),我可以做些什么来允许它?

我正在使用 Windows。

【问题讨论】:

同时发送?还是在不同的时间发送? @thang 同时。 如果它是一个流套接字,你有一个问题是让流有意义...... @thang 你的意思是缓冲区可以混合在一起? @Tom 如果您使用 UDP,您可以摆脱它,因为每次调用 send() 都会产生一个单独的 UDP 数据包。对于 TCP,它只有在每次调用 send() 都包含完整的消息时才有效;否则来自两个线程的消息交错将混淆远程客户端中的解析器。但问题是 send() 可以在没有发送您要求它发送的所有数据的情况下返回——这意味着您不能保证每次调用 send() 都会包含完整的消息!所以对于 TCP,指定一个线程来处理发送,并让另一个线程转发给发送者线程。 【参考方案1】:

根本原因是同步 I/O 函数使用句柄对象(套接字实现为句柄)来跟踪 I/O 是否完成。

结果是,如果你尝试从多个线程同时向同一个套接字发送(),send() 可能会在 I/O 实际完成之前 (a) 挂起或 (b) 退出,从而导致灾难性的结果.

您可以使用临界区来防止发送重叠,或​​者指定一个线程来读取要从队列发送的数据。

请注意,这仅适用于发送到 same 套接字的情况。同时发送到不同的个套接字是可以的。

【讨论】:

注意 - 这是 Windows 上同步 I/O 的一般规则。 可能套接字库是一个例外,可能是为了与 Posix 套接字兼容。但是,除非有人能找到明确说明这一点的文档,否则我不会指望它。 Posix 要求 send() 是原子的,并在阻塞模式下在单个调用中完成写入,并且 Windows 旨在与 Posix 兼容。几年前,几个实现者对 news:comp.protocols.tcp-ip 进行了广泛的讨论,这是一般结论。 @EJP:Windows 通常不符合 Posix。您是指仅就套接字实现而言吗?

以上是关于在来自多个线程的阻塞套接字上使用 send()的主要内容,如果未能解决你的问题,请参考以下文章

C++ 套接字 Send() 线程安全

非阻塞套接字轮询与阻塞套接字

C++ winsock服务器中非阻塞模式与异步套接字的区别

TCP阻塞模型下服务器和客户端的建立步骤

如何立即终止套接字 IO 操作上的线程阻塞?

ZMQ:socket_send/recv 阻塞