TCPソケットサーバが動作不能になるまで時間が経つにつれて時折CLOSE_WAITsを構築します

StackOverflow https://stackoverflow.com/questions/679643

質問

私たちは限り調査が行くことができるように達しているとうまくいけば、誰かが私たちを助けることができる!

私たちは、ASP.NET Webアプリケーションからの接続を受け入れるC#で書かれたシンプルな非同期ソケットサーバーを持っているメッセージを送信し、(通常はあまりにもDBが、他のシステムに対して)いくつかの処理を行い、その後、戻って応答を送信しますクライアントへ。クライアントが接続を閉じるの担当している。

私たちは、システムがプロセスを受け入れない程度に(通常日)、CLOSE_WAITソケットがサーバーボックスに蓄積時間(のnetstat -a)の長期間にわたって負荷が大きい場合には問題を抱えてきましたそれ以上の接続。その時点で、私たちは、プロセスをバウンスする必要がオフそれが再び実行されます。

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

  

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

私は(ASP.NETアプリケーションが行うのと同じコードを使用して)直接ソケットサーバーに話してシングルスレッドのプロセスとしてパケットトレースから問題を再現しようとしたができませんしました。

誰もが、試すためにチェックするか、我々は間違っていることがあります?

明白なものするために、次のものの任意の提案を持っています
役に立ちましたか?

解決

の図を見てください。

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

あなたのクライアントは、FIN、今CLOSE_WAITに変更の状態をACKさサーバソケットにFINを送った()closeを呼び出して接続を閉じ、およびサーバーの問題でclose()その上で呼び出さない限り、そのようにとどまりますソケットます。

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

他のヒント

お使いのサーバがCLOSE_WAITソケットを蓄積している場合は、接続が完了すると、

それはそのソケットを閉じていません。あなたがクリスの記事にコメントして状態図を見てみる場合は、ソケットが閉じられ、CLOSE_WAITが送られた後LAST_ACKすることFIN遷移が表示されます。

あなたはそれがどこ非同期な性質のためにこれを実行するかを決定するために複雑だと言いますか?これはあなたのrecvからのコールバックは、(あなたのクライアントは、接続のその側を閉じた後、あなたが行うには何もしていないと仮定した場合)0バイトを返す場合は、ソケットを閉じる必要があり、問題になることはありません。あなたがシャットダウン(送信)とを行う送信完了したら、あなたのクライアントは、閉じられたことをここにシャットダウン(RECV)を行い、その後に送信し、ノートを作るために継続を心配する必要がない場合は閉じるます。

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

  

クライアントが接続を閉じるの担当している。

クライアントとサーバの両方がソケットを閉じて、シャットダウンしなければなりません。どちらのクライアントが近くに仕上げていません。(そう - それはファイナライザの実行です必要があると思いますので)またはサーバーが(おそらく)ソケットをシャットダウンされていません。

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

あなただけのクライアントまでのTCPソケットを閉じるの責任を残すべきではありません。クライアント・プロセス/マシンがクラッシュした場合はどうなりますか?

トラフィックが一定時間後に接続されたソケット上で受信されない場合、それがサーバーによって閉じられますように

理想的には、代わりにタイムアウトを持っている必要があります。

どんなにソケット上のすべての操作がクライアントによって終了している、それは、クライアントがcloseコマンドを発行する必要があり、ソケット上の任意のより多くの読み取り操作を行う必要はありませんときに何が起こりますか。

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

サーバが再びリードコマンド(非同期モードでlistener.read()またはlistener.beginread(...))を発行し、簡単な言葉では、読み取りは、0バイトが読ま戻ります、これは自分自身であることを示しソケットは、ソケットの他の操作は、クライアントによって停止したとして、リスナーによって閉じする必要があります。

CLOSE_WAITのソケットが閉じられた後に、同じソケット番号を再使用して、古い接続からのパケットを受信防ぐために、しばらくの間、周りにハングアップすることが意図されています。これは、あなたが本当にすぐソケットのhuuuuge数を開閉している場合、あなたは悲しみ与えるだろう。

EDIT - 。それは上記CLOSE_WAIT、TIME_WAITすべきではない。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top