【发布时间】:2014-04-10 01:16:55
【问题描述】:
我有一个服务器应用程序,它使用Microsoft's I/O Completion Port (IOCP) 机制来管理异步网络套接字通信。总的来说,这种 IOCP 方法在我的环境中表现得非常好。但是,我遇到了一个极端情况,我正在寻求指导:
出于测试目的,我的服务器应用程序正在通过千兆位 LAN 将数据流式传输(比如说 ~400 KB/秒)到单个客户端。一切都很好……直到我断开客户端的以太网电缆与 LAN 的连接。以这种方式断开电缆可防止服务器立即检测到客户端已消失(即客户端的 TCP 网络堆栈不会向服务器发送连接终止的通知)
同时,服务器继续向客户端发出WSASend 调用...由于这些调用是异步的,它们似乎“成功”(即数据由操作系统在套接字的出站队列中缓冲)。
虽然这一切都在发生,但我有 16 个线程在 GetQueuedCompletionStatus 上阻塞,等待从端口检索完成数据包,因为它们变得可用。在断开客户端的电缆之前,有源源不断的完成数据包流。现在,一切(如预期)似乎都停止了……大约 32 秒。 32 秒后,IOCP 重新开始操作,返回具有非空 lpOverlapped 值的 FALSE。 GetLastError 返回 121(信号量超时期限已过。)我只能假设错误 121 是 WSASend 在 TCP 堆栈确定客户端消失后最终超时的工件?
网络堆栈需要 32 秒才能确定我的客户端已消失,这很好。问题是,当系统做出这个决定时,我的 IOCP 瘫痪了。例如,在收到失败的完成数据包(指示错误 121)之前,GetQueuedCompletionStatus 上阻塞的 16 个线程中的任何一个都不会处理发布到同一 IOCP 的 WSAAccept 事件。
我最初的解决此问题的计划涉及在致电WSASend 后立即使用WSAWaitForMultipleEvents。如果套接字事件在(例如 3 秒)内没有发出信号,那么我终止套接字连接并继续前进(希望防止对我的 IOCP 产生广泛的阻塞影响)。不幸的是,WSAWaitForMultipleEvents 似乎永远不会遇到超时(所以异步套接字可能是由于异步而发出信号的?或者将数据复制到 TCP 队列有资格获得信号?)
我仍在尝试解决这一切,但希望有人对如何防止 IOCP 挂起有所了解。
其他细节:我的服务器应用程序运行在 8 核的 Win7 上; IOCP配置为最多使用8个并发线程;我的线程池有 16 个线程。充足的 RAM、处理器和带宽。
提前感谢您的建议和建议。
【问题讨论】:
-
这听起来不对。
WSAAccept()不依赖于首先处理的WSASend()。特别是因为这两个函数是在两个单独的SOCKET句柄上调用的。如果WSAAccept()有一个待处理的客户端,它将发布一个IOCP 事件,而WSASend()继续在后台工作。这让我觉得你没有正确管理 IOCP。请出示您的实际代码。 -
我认为这是您的代码的一个错误,因为 IOCP 不可能那么坏。尝试用几十行创建一个简单的复制品并将其发布在此处。我的猜测:在这个过程中你会自己发现这个错误。
-
感谢您的建议。事实上,这个问题被证明是虚假的。我不知道,混合中确实有两个 IOCP(一个由使用相同线程代码的同事添加)。这两个 IOCP 之间的交互导致产生错误行为的死锁。现在一切都很顺利。
标签: winsock2 iocp overlapped-io