0

Microsoft の I/O Completion Port (IOCP)メカニズムを使用して非同期ネットワーク ソケット通信を管理するサーバー アプリケーションがあります。一般に、この IOCP アプローチは、私の環境では非常にうまく機能しています。ただし、ガイダンスを求めているエッジ ケース シナリオに遭遇しました。

テストの目的で、私のサーバー アプリケーションは、ギガビット LAN を介して単一のクライアントにデータをストリーミングしています (たとえば、約 400 KB/秒)。クライアントのイーサネット ケーブルを LAN から切断するまでは、すべて問題ありません。この方法でケーブルを切断すると、クライアントが消えたことをサーバーがすぐに検出できなくなります (つまり、クライアントの TCP ネットワーク スタックは、接続の終了の通知をサーバーに送信しません)。

その間、サーバーはクライアントへの呼び出しを続けWSASendます...これらの呼び出しは非同期であるため、「成功」したように見えます (つまり、データは OS によってソケットのアウトバウンド キューにバッファリングされます)。

これがすべて起こっている間、私は で 16 個のスレッドをブロックしGetQueuedCompletionStatus、ポートから完了パケットが利用可能になったときにそれらを取得するのを待っています。クライアントのケーブルを切断する前に、完了パケットの絶え間ないストリームがありました。ここで、(予想どおり) すべてが停止したように見えます... 約 32 秒間。32 秒後、IOCP は再びアクションを開始FALSEし、null 以外のlpOverlapped値を返します。 GetLastError121 を返します (セマフォのタイムアウト期間が終了しました。) エラー 121 はWSASend、クライアントがなくなったと TCP スタックが判断した後、最終的にタイムアウトになったというアーティファクトだとしか思えません。

クライアントがなくなったことを把握するためにネットワーク スタックが 32 秒かかっても問題ありません。問題は、システムがこの決定を行っている間、私の IOCP が麻痺していることです。たとえばWSAAccept、同じ IOCP に投稿されるイベントはGetQueuedCompletionStatus、失敗した完了パケット (エラー 121 を示す) が受信されるまで、ブロックされている 16 のスレッドのいずれによっても処理されません。

これを回避するための私の最初の計画はWSAWaitForMultipleEvents、 を呼び出した直後にを使用することWSASendでした。ソケット イベントが (たとえば 3 秒) 以内に通知されなかった場合は、ソケット接続を終了して先に進みます (IOCP への広範なブロック効果を防ぐため)。残念ながら、WSAWaitForMultipleEventsタイムアウトに遭遇することはないようです (したがって、非同期ソケットは非同期であるという理由でシグナルを送信されるのでしょうか? または、TCP キューへのデータのコピーがシグナルの対象となりますか?)

私はまだこれをすべて整理しようとしていますが、IOCP ハングを防ぐ方法について誰かが洞察を持っていることを望んでいました。

その他の詳細: 私のサーバー アプリケーションは、8 コアの Win7 で実行されています。IOCP は最大 8 つの同時スレッドを使用するように構成されています。私のスレッドプールには 16 個のスレッドがあります。十分な RAM、プロセッサ、および帯域幅。

ご提案やアドバイスをよろしくお願いします。

4

1 に答える 1

2

WSASend()この状況で完了が停止するのは、通常のことです。TCP スタックが再送信の試行をタイムアウトし、すべての未処理の送信がエラーで完了するまで、それらを取得することはできません。これにより、他の操作がブロックされることはありません。テストが間違っているか、コードにバグがあると思います。

あなたの「修正」には欠陥があることに注意してください。送信者が消費者が消費できるよりも速く送信している場合、通常の接続中の任意の時点で、この「送信完了の遅延」状況が発生する可能性があります。TCP フロー制御と非同期書き込みに関するこの記事を参照してください。より良い計画は、許可する (接続ごとの) 未処理の書き込みの量にカウンターを使用し、そのカウンターに達した場合は送信を停止し、「低水準点」のしきい値を下回ったときに再開することです。

ネットワーク ケーブルをマシンに引き抜いた場合、他の操作はどのように完了すると予想されるのでしょうか? 読み取りはそこに留まり、書き込みが失敗した場合にのみ失敗し、AcceptEx はそのままそこに留まり、状態が修正されるのを待ちます。

于 2014-04-10T12:13:11.970 に答える