【问题标题】:How to prevent an I/O Completion Port from blocking when completion packets are available?当完成数据包可用时,如何防止 I/O 完成端口阻塞?
【发布时间】: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 值的 FALSEGetLastError 返回 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


【解决方案1】:

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

请注意,您的“修复”存在缺陷。如果发件人的发送速度快于消费者的消费速度,您可以在正常连接期间的任何时候看到这种“延迟发送完成”的情况。见this article on TCP flow control and async writes。更好的计划是使用一个计数器来记录您希望允许的未完成写入(每个连接)的数量,并在达到该计数器时停止发送,然后在它降至“低水位线”阈值以下时恢复。

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

【讨论】:

  • 嗨 Len,感谢您确认 WSASend 在这种情况下停滞不前。
  • 奇怪行为的原因:一位同事添加了一个我不知道的辅助 IOCP。他们一起启用了导致我头痛的情况的死锁情况。我已经修复了代码,现在一切正常。再次感谢您的反馈以及您在您的网站上提供的精彩文章。
  • 顺便说一句:在发布这个问题之前,我通过谷歌看到了你的流量控制文章——写得很好。我的项目计划使用流控制,但我还没有实现它。另外,我很抱歉不清楚拉了哪根网线——ClientA 的网线被拉了,而 ClientB 和服务器的网络保持完好。再次感谢您的反馈。
猜你喜欢
  • 2011-02-17
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 2011-03-03
相关资源
最近更新 更多