2009-03-24 50 views
3

調査ができる限り、誰かが私たちの手助けをしてくれることを願っています。TCPソケットサーバがCLOSE_WAITを構築することがあります。動作しなくなるまで時間がたつにつれて

私たちは、ASP.NET Webアプリケーションからの接続を受け付け、メッセージを送信し、何らかの処理を行い(通常はDB以外のシステムに対しても)、応答を送信するC#で書かれた単純な非同期ソケットサーバーを持っています。クライアントに返します。クライアントは接続を閉じることを担当しています。

システムに長期間(通常は数日間)負荷がかかる場合、CLOSE_WAITソケットはサーバーのボックス(netstat -a)にプロセスが作成されない程度に蓄積されていましたそれ以上の接続は受け入れます。その時点でプロセスをバウンスさせなければならず、プロセスが再び実行されます。

私たちはASP.NETアプリケーションのいくつかの負荷テストを実行して問題を再現しようとしました(コードからのいくつかの問題を推測できなかったため)。私たちは、これを管理し、ソケットサーバのログでのSocketExceptionとしての地位を明示する問題のWireSharkのpacket traceになってしまったと思う:

System.Net.Sockets.SocketException:既存の接続が強制的に切断されましたSystem.Net.Sockets.Socket.BeginSend(バイト[]バッファのInt32オフセット、のInt32のサイズ、socketFlags socketFlags、AsyncCallbackコールバック、オブジェクトの状態)で、リモートホストは

Iから問題を再現しようとしました(ASP.NETアプリケーションと同じコードを使用して)ソケットサーバーに直接通話する単一のスレッドプロセスとしてのパケットトレースは不可能です。

私たちが間違っている可能性があることを、誰かが試してみてください。

答えて

5

ルックは

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

あなたのクライアントは、FIN、今CLOSE_WAITに変更の状態、および滞在をACKさサーバソケットにFINを送った()closeを呼び出して接続を閉じサーバーがそのソケットでclose()呼び出しを発行しない限り、その方法です。

サーバープログラムは、クライアントが接続を中止したかどうかを検出し、すぐにポートを解放してポートを解放する必要があります。どうやって? read()を参照してください。ファイルの終わり(FINが受信されたことを意味する)を読み取ると、ゼロが返されます。

3

クライアントが接続を終了しています。

クライアントとサーバーの両方がソケットを閉じてシャットダウンする必要があります。クライアントがクローズを完了していないか(おそらく、ファイナライザが実行されているため)、またはサーバがソケットをシャットダウンしていない(おそらく)。のは、ソケットが閉じられた後に、同じソケット番号を再使用して、古い接続からのパケットを受信防ぐために、しばらくの間、周りにハングアップすることを意図している

using (Socket s = new Socket(/* */)) { 
    /* Do stuff */ 
    s.Shutdown(SocketShutdown.Both); 
    s.Close(); 
} 
+0

ソケットは使用(..)ブロックの一部として閉じられますが、現時点ではシャットダウンと.Closeを明示的に実行していません。通常のテストでは問題はありません。サーバーは、私たちが見つけることができるすべてのコードパスで明示的に両方を行います(非同期なので複雑です)。 –

+0

@Kieran - サーバープロセスをバウンスするとCLOSE_WAITがクリアされるという事実は、あなたがどこかで閉じていないことを示していると私は思う。 –

-2

CLOSE_WAIT。あなたが本当にすばらしい数のソケットを開いたり閉じたりしている場合、これはあなたに悲しみを与えます。

EDIT - 上記のCLOSE_WAITではなくTIME_WAITである必要があります。

+0

何らかの理由で接続がくさびれている場合、それ以上の時間がかかります。http://blog.zhuzhaoyuan.com/2009/03/a-word-on-time_wait-and-close_wait/を参照してください。それはTIME_WAITのような自然なものではありません。 –

+0

close_waitとtime_waitが混乱しているのですか? – Chris

+1

あなたはTIME_WAITのクリスを考えています。 –

0

TCPソケットをクライアントまで閉じることは、絶対に行わないでください。クライアントプロセス/マシンがクラッシュした場合はどうなりますか?

一定の時間が経過しても接続されたソケットでトラフィックが受信されない場合は、サーバーによって閉じられるように、タイムアウトを設定するのが理想的です。

5

サーバがCLOSE_WAITのソケットを累積している場合、接続が完了してもソケットは閉じていません。 Chrisの投稿へのコメントの状態図を見ると、ソケットが閉じてFINが送信された後には、CLOSE_WAITLAST_ACKに移行することがわかります。

あなたは、非同期性のためにこれを行う場所を決定するのは複雑ですか?これは問題ではないはずです。recvのコールバックが0バイトを返す場合は、ソケットを閉じる必要があります(クライアントが接続の側を閉じると何もしないと仮定します)。送信を続行することを心配する必要がある場合は、ここでシャットダウン(recv)を実行し、クライアントが終了したことをメモします。終了すると、シャットダウン(送信)とクローズを行います。

あなたはクライアントが閉じていることを示す0を返す読み込みからコールバックで新しい読み込みを発行することがありますが、これは問題を引き起こしている可能性がありますか?図で

0

ソケットのすべての操作がクライアントによって終了しても、ソケットでの読み取り操作を行う必要はありません。クライアントはcloseコマンドを発行する必要があります。

このcloseコマンドを発行すると、リスナー(サーバー)に接続をシャットダウンする必要があることが通知されます。

単純に言えば、サーバが非同期モードでreadコマンド(listener.read()またはlistener.beginread(...))を再度発行すると、readは0バイトの読み込みを返します。リスナーによってソケットを閉じる必要があります。これは、ソケット上の他の操作がクライアントによって中止されたためです。

関連する問題