0

我有一个服务器应用程序,它使用Microsoft 的 I/O 完成端口 (IOCP)机制来管理异步网络套接字通信。总的来说,这种 IOCP 方法在我的环境中表现得非常好。但是,我遇到了一个极端情况,我正在寻求指导:

出于测试的目的,我的服务器应用程序正在通过千兆位 LAN 将数据流式传输(比如说 ~400 KB/秒)到单个客户端。一切都很好……直到我断开客户端的以太网电缆与 LAN 的连接。以这种方式断开电缆可防止服务器立即检测到客户端已消失(即客户端的 TCP 网络堆栈不会向服务器发送连接终止的通知)

同时,服务器继续对WSASend客户端进行调用......由于这些调用是异步的,它们似乎“成功”(即数据由操作系统缓冲在套接字的出站队列中)。

虽然这一切都在发生,但我有 16 个线程被阻塞GetQueuedCompletionStatus,等待从端口检索完成数据包,因为它们变得可用。在断开客户端的电缆之前,有源源不断的完成数据包流。现在,一切(如预期)似乎都停止了……大约 32 秒。32 秒后,IOCP 重新开始操作,返回FALSE一个非空lpOverlapped值。 GetLastError返回121(信号量超时期限已过。)我只能假设错误121是WSASendTCP堆栈确定客户端消失后最终超时的产物?

我很好,网络堆栈需要 32 秒才能确定我的客户端已经消失。问题是,当系统做出这个决定时,我的 IOCP 瘫痪了。例如,在接收到失败的完成数据包(指示错误 121)之前,WSAAccept被阻塞的 16 个线程中的任何一个都不会处理发布到同一 IOCP 的事件。GetQueuedCompletionStatus

我最初的解决这个问题的计划涉及WSAWaitForMultipleEvents在调用后立即使用WSASend。如果套接字事件没有在(例如 3 秒)内发出信号,那么我终止套接字连接并继续前进(希望防止对我的 IOCP 产生广泛的阻塞效应)。不幸的是,WSAWaitForMultipleEvents似乎从来没有遇到过超时(所以异步套接字可能是由于异步而发出信号的?或者将数据复制到 TCP 队列有资格获得信号?)

我仍在尝试解决这一切,但希望有人对如何防止 IOCP 挂起有一些见解。

其他细节:我的服务器应用程序在 8 核的 Win7 上运行;IOCP配置为最多使用8个并发线程;我的线程池有 16 个线程。大量的 RAM、处理器和带宽。

提前感谢您的建议和建议。

4

1 回答 1

2

在这种情况下,完成通常WSASend()会停滞不前。在 TCP 堆栈超时重新发送尝试并错误地完成所有未完成的发送之前,您不会得到它们。这不会阻止任何其他操作。我希望您要么测试不正确,要么代码中有错误。

请注意,您的“修复”是有缺陷的。如果发件人的发送速度快于消费者的消费速度,您可以在正常连接期间的任何时候看到这种“延迟发送完成”的情况。请参阅这篇关于 TCP 流控制和异步写入的文章。一个更好的计划是使用计数器来记录您希望允许的未完成写入(每个连接)的数量,并在达到该计数器时停止发送,然后在它低于“低水位线”阈值时恢复。

请注意,如果您已将网线拔入机器,您希望其他操作如何完成?读取只会坐在那里,只有在写入失败时才会失败,AcceptEx 只会坐在那里等待条件自行纠正。

于 2014-04-10T12:13:11.970 回答