Twistedには、上に実装されたリアクターMsgWaitForMultipleObjects
が含まれます。どうやら、少なくともピアがいくつかのバイトを送信してからすぐに接続を閉じる場合、reactorにはTCP接続がいつ終了するかを確実に通知する問題があります。何が起こっているようです:
- リアクタは
MsgWaitForMultipleObjects
、いくつかのソケットハンドルとを使用して呼び出しますQS_ALLINPUT
。 - 呼び出しが完了し、この状態のソケットのハンドルがアクティブであることを示します(つまり、バイトが読み取られるのを待機していて、ピアによって閉じられています)。
- リアクタは、この通知を一般的な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
は、基本的に1回限りのイベントであることを指摘するなど、ここで何が起こっているかについてもう少し説明しています。一度信号を送った後は、二度とそれを取得することはありません。これは、Twistedにこの問題がある理由を説明するのに役立ちます。MsgWaitForMultipleObjects
ただし、この制限を考慮して、効果的に使用する方法については、まだ興味があります。