在来自多个线程的阻塞套接字上使用 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()的主要内容,如果未能解决你的问题,请参考以下文章