一些使用 WSASend 的 OVERLAPS 没有使用 GetQueuedCompletionStatus 及时返回?

Posted

技术标签:

【中文标题】一些使用 WSASend 的 OVERLAPS 没有使用 GetQueuedCompletionStatus 及时返回?【英文标题】:some OVERLAPS using WSASend not returning in a timely manner using GetQueuedCompletionStatus? 【发布时间】:2009-07-17 19:30:29 【问题描述】:

背景:我正在使用 CreateIoCompletionPort、WSASend/Recv 和 GetQueuedCompletionStatus 在我的服务器上执行重叠套接字 io。对于流控制,当发送到客户端时,我只允许在所有挂起的 OVERLAP 都从 IOCP 中弹出时调用几个 WSASend()。

问题:最近,有一些情况是 OVERLAP 没有返回到 IOCP。调用 GetQueuedCompletionStatus 的线程没有得到它们,它们保留在我的本地挂起队列中。我已经验证客户端确实从套接字接收数据并且套接字已连接。进行 WSASend() 调用时没有返回错误。在没有如下外部刺激的情况下,重叠只是“永远不会”回来:

    从客户端或服务器断开套接字,立即允许 GetQueuedCompletionStatus 线程检索重叠 在所有 OVERLAP 突然从队列中弹出之前,有时需要多次调用 WSASend()。

问题:有人见过这种行为吗?关于造成这种情况的任何想法?

谢谢, 杰弗里

【问题讨论】:

你的应用是单线程的还是多线程的? 它是多线程的。一个线程循环,只调用GetQueuedCompletionStatus,回收OVERLAP。如果设置了事件,另一个线程使用 WaitForSingleObject(100 毫秒的短暂超时)并调用 WSASend()。 【参考方案1】:

如果 TCP 窗口已满,WSASend() 可能无法及时完成。在这种情况下,堆栈无法发送更多数据,因此您的 WSASend() 会等待,直到 TCP 堆栈可以发送更多数据后才会完成。

如果您的客户端和服务器之间碰巧有一个协议,该协议本身没有内置流量控制,并且您自己没有根据写入完成进行任何流量控制,并且只是尽可能快地发送数据发送然后您可能会到达网络或您的客户端无法跟上并且TCP流控制启动(当TCP窗口已满时)的地步。如果您继续通过对WSASend() 的额外调用来异步触发数据,那么最终您将在机器上的所有非分页内存中咀嚼,此时所有的赌注都被关闭(驱动程序的可能性很高可能会导致盒子蓝屏)。

因此,总而言之,重叠套接字写入的完成可能而且有时需要比您预期的更长的时间才能返回。在您的示例中,我希望您在关闭套接字时获得的完成都是失败的?

我在我的博客上谈了更多;这里:http://www.lenholgate.com/blog/2008/07/write-completion-flow-control.html 和这里:http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html

【讨论】:

以上是关于一些使用 WSASend 的 OVERLAPS 没有使用 GetQueuedCompletionStatus 及时返回?的主要内容,如果未能解决你的问题,请参考以下文章

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

io 完成端口问题,每个 GetQueuedCompletionStatus 调用多个 wsarecv 或 wsasend

IOCP 服务器并使用单个 wsasend 发送数据

我可以反复调用 WSASend() 吗?

TCP WSASend 完成标准

readv()、writev()、WSARecv()、WSASend()