Twisted包括一个基于
MsgWaitForMultipleObjects
实现的反应器。 显然,反应器在可靠地注意到TCP连接结束时存在问题,至少在对等方发送一些字节然后快速关闭连接的情况下是如此。 看起来发生的是:
- 反应堆使用一些套接字句柄和 QS_ALLINPUT 调用 MsgWaitForMultipleObjects。
- 调用完成并指示处于此状态的套接字句柄(即等待读取且已被对等方关闭)处于活动状态。
- 反应堆将此通知分派给常见的 TCP 实现。
- TCP 实现从套接字中读取可用字节。有一些字节,它们被传递到应用程序代码。
- 控制权返回到反应堆,最终再次调用 MsgWaitForMultipleObjects。
- MsgWaitForMultipleObjects 永远不会再次指示该句柄处于活动状态。TCP 实现永远无法再次查看套接字,因此无法检测到连接已关闭。
MsgWaitForMultipleObjects
看起来像是一种边缘触发通知机制。MSDN文档中说:Waits until one or all of the specified objects are in the signaled state
or the time-out interval elapses.
这听起来不像是边缘触发,而更像是电平触发。
MsgWaitForMultipleObjects
真的是边缘触发吗?还是它是电平触发,而这种错误行为是由其行为的某些其他方面引起的?
附录 WSAEventSelect 的 MSDN 文档 更详细地解释了这里正在发生的事情,包括指出 FD_CLOSE
基本上是一次性事件。一旦它被触发,你就再也不会收到它了。这在一定程度上解释了为什么 Twisted 会有这个问题。尽管如此,我仍然很想知道如何有效地使用 MsgWaitForMultipleObjects
来克服这个限制。