Microsoft の I/O Completion Port (IOCP)メカニズムを使用して非同期ネットワーク ソケット通信を管理するサーバー アプリケーションがあります。一般に、この IOCP アプローチは、私の環境では非常にうまく機能しています。ただし、ガイダンスを求めているエッジ ケース シナリオに遭遇しました。
テストの目的で、私のサーバー アプリケーションは、ギガビット LAN を介して単一のクライアントにデータをストリーミングしています (たとえば、約 400 KB/秒)。クライアントのイーサネット ケーブルを LAN から切断するまでは、すべて問題ありません。この方法でケーブルを切断すると、クライアントが消えたことをサーバーがすぐに検出できなくなります (つまり、クライアントの TCP ネットワーク スタックは、接続の終了の通知をサーバーに送信しません)。
その間、サーバーはクライアントへの呼び出しを続けWSASend
ます...これらの呼び出しは非同期であるため、「成功」したように見えます (つまり、データは OS によってソケットのアウトバウンド キューにバッファリングされます)。
これがすべて起こっている間、私は で 16 個のスレッドをブロックしGetQueuedCompletionStatus
、ポートから完了パケットが利用可能になったときにそれらを取得するのを待っています。クライアントのケーブルを切断する前に、完了パケットの絶え間ないストリームがありました。ここで、(予想どおり) すべてが停止したように見えます... 約 32 秒間。32 秒後、IOCP は再びアクションを開始FALSE
し、null 以外のlpOverlapped
値を返します。 GetLastError
121 を返します (セマフォのタイムアウト期間が終了しました。) エラー 121 はWSASend
、クライアントがなくなったと TCP スタックが判断した後、最終的にタイムアウトになったというアーティファクトだとしか思えません。
クライアントがなくなったことを把握するためにネットワーク スタックが 32 秒かかっても問題ありません。問題は、システムがこの決定を行っている間、私の IOCP が麻痺していることです。たとえばWSAAccept
、同じ IOCP に投稿されるイベントはGetQueuedCompletionStatus
、失敗した完了パケット (エラー 121 を示す) が受信されるまで、ブロックされている 16 のスレッドのいずれによっても処理されません。
これを回避するための私の最初の計画はWSAWaitForMultipleEvents
、 を呼び出した直後にを使用することWSASend
でした。ソケット イベントが (たとえば 3 秒) 以内に通知されなかった場合は、ソケット接続を終了して先に進みます (IOCP への広範なブロック効果を防ぐため)。残念ながら、WSAWaitForMultipleEvents
タイムアウトに遭遇することはないようです (したがって、非同期ソケットは非同期であるという理由でシグナルを送信されるのでしょうか? または、TCP キューへのデータのコピーがシグナルの対象となりますか?)
私はまだこれをすべて整理しようとしていますが、IOCP ハングを防ぐ方法について誰かが洞察を持っていることを望んでいました。
その他の詳細: 私のサーバー アプリケーションは、8 コアの Win7 で実行されています。IOCP は最大 8 つの同時スレッドを使用するように構成されています。私のスレッドプールには 16 個のスレッドがあります。十分な RAM、プロセッサ、および帯域幅。
ご提案やアドバイスをよろしくお願いします。