我有一个服务器应用程序,它使用Microsoft 的 I/O 完成端口 (IOCP)机制来管理异步网络套接字通信。总的来说,这种 IOCP 方法在我的环境中表现得非常好。但是,我遇到了一个极端情况,我正在寻求指导:
出于测试的目的,我的服务器应用程序正在通过千兆位 LAN 将数据流式传输(比如说 ~400 KB/秒)到单个客户端。一切都很好……直到我断开客户端的以太网电缆与 LAN 的连接。以这种方式断开电缆可防止服务器立即检测到客户端已消失(即客户端的 TCP 网络堆栈不会向服务器发送连接终止的通知)
同时,服务器继续对WSASend
客户端进行调用......由于这些调用是异步的,它们似乎“成功”(即数据由操作系统缓冲在套接字的出站队列中)。
虽然这一切都在发生,但我有 16 个线程被阻塞GetQueuedCompletionStatus
,等待从端口检索完成数据包,因为它们变得可用。在断开客户端的电缆之前,有源源不断的完成数据包流。现在,一切(如预期)似乎都停止了……大约 32 秒。32 秒后,IOCP 重新开始操作,返回FALSE
一个非空lpOverlapped
值。 GetLastError
返回121(信号量超时期限已过。)我只能假设错误121是WSASend
TCP堆栈确定客户端消失后最终超时的产物?
我很好,网络堆栈需要 32 秒才能确定我的客户端已经消失。问题是,当系统做出这个决定时,我的 IOCP 瘫痪了。例如,在接收到失败的完成数据包(指示错误 121)之前,WSAAccept
被阻塞的 16 个线程中的任何一个都不会处理发布到同一 IOCP 的事件。GetQueuedCompletionStatus
我最初的解决这个问题的计划涉及WSAWaitForMultipleEvents
在调用后立即使用WSASend
。如果套接字事件没有在(例如 3 秒)内发出信号,那么我终止套接字连接并继续前进(希望防止对我的 IOCP 产生广泛的阻塞效应)。不幸的是,WSAWaitForMultipleEvents
似乎从来没有遇到过超时(所以异步套接字可能是由于异步而发出信号的?或者将数据复制到 TCP 队列有资格获得信号?)
我仍在尝试解决这一切,但希望有人对如何防止 IOCP 挂起有一些见解。
其他细节:我的服务器应用程序在 8 核的 Win7 上运行;IOCP配置为最多使用8个并发线程;我的线程池有 16 个线程。大量的 RAM、处理器和带宽。
提前感谢您的建议和建议。