我应该同时进行 WSASend() 调用吗?

Posted

技术标签:

【中文标题】我应该同时进行 WSASend() 调用吗?【英文标题】:Should I make simultaneous WSASend() calls? 【发布时间】:2015-03-05 11:28:32 【问题描述】:

我知道为了同时调用WSASend(),我需要为每个调用提供一个唯一的WSAOVERLAPPEDWSABUF 实例。但这意味着我必须为每次调用跟踪这些实例,这会使事情变得复杂。

我认为,如果我创建一个线程来不是同时调用,而是顺序调用,那将是一个更好的主意。该线程将等待一个队列,该队列将持有WSASend() 请求(每个请求将包含套接字句柄和我要发送的字符串)。当我最终调用WSASend() 时,我将阻塞线程,直到我收到来自等待完成端口的线程的唤醒信号,告诉我WSASend() 已经完成,然后我继续获取下一个请求。

如果这是个好主意,那么我应该如何实现队列以及如何对其进行阻塞提取调用(而不是使用轮询)?

【问题讨论】:

第一个问题是对等方是否能够理解所有这些并发发送。真的可以吗? @EJP 是的,每个WSASend() 调用都会发送一条定义长度且彼此不相关的消息。 听起来你应该对我使用阻塞 I/O,并使用互斥锁对其进行序列化。比你在这里提出的要简单得多。 @EJP 但是我想处理成千上万的客户端,所以阻塞 I/O 是行不通的。 如果你打算使用发送者线程,你可以在排队/出队时使用同步机制来锁定队列。应该够了。 【参考方案1】:

WSABUF 可以基于堆栈,因为WSASend() 负责在返回之前复制它。 OVERLAPPED 和数据缓冲区本身必须存在,直到提取和处理操作的 IOCP 完成。

我一直使用“扩展”OVERLAPPED 结构,它包含数据缓冲区、重叠结构和WSABUF。然后,我使用引用计数系统来确保“每个操作数据”一直存在,直到没有人需要它为止(也就是说,我在 API 调用启动操作之前获取引用,并在删除操作完成后释放引用从 IOCP 完成 - 请注意,这里的引用不是 100% 必需的,但它们可以更容易地将生成的数据缓冲区传递给代码的其他部分)。

对于 TCP 连接来说,在任何时候传输数据的 TCP“窗口大小”并有更多的待处理数据是最优化的,这样窗口总是保持满,并且总是以最大发送连接可以采取。要通过重叠 I/O 实现这一点,通常最好有许多 WSASend() 调用待处理。但是,您不希望有太多待处理(请参阅here),实现这一点的最简单方法是跟踪您待处理的字节数、队列字节以供以后传输并在存在时从传输队列发送发送完成...

【讨论】:

以上是关于我应该同时进行 WSASend() 调用吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该为 WSASend 和 WSARecv 使用不同的 WSAOVERLAPPED 结构吗?

GQCS 收到通知,当 WSAsend 返回 0 时?

WSASend() 和 WSARecv() 的所有错误代码是不是意味着套接字已断开连接?

具有多个缓冲区的 WSASend() - 可以完成不完整吗?

我应该处理 WSASend() 可能不会发送所有数据的事实吗?

在迂回的 WSASend 中阻塞数据包