CLOSE_WAITソケット接続を削除するにはどうすればよいですか


91

特定のポートでサーバーと対話する小さなプログラムを作成しました。プログラムは正常に動作しますが、次のようになります。

プログラムが予期せず終了した後、そのソケット接続がCLOSE_WAIT状態で表示されてから。プログラムを実行しようとすると、ハングし、強制的に閉じる必要があり CLOSE_WAITます。これにより、さらに多くのソケット接続が蓄積されます。

これらの接続をフラッシュする方法はありますか?


4
あなたはできません(そしてすべきではありません)。CLOSE_WAITは、相手がこれを確認するのを待って閉じられている接続に対してTCPによって定義された状態です。
vonbrand 2013

1
unix.stackexchange.com/questions/10106/… ...も参照してください。これは、トピックから外れたものとして質問を閉じることになるため、重複として投票することはありません。
derobert 2013

3
@vonbrandいいえ、そうではありません。正反対です。これは、ピアによってすでに閉じられており、ローカルアプリケーションがその終了を閉じるのを待っている接続の状態です。
ローン侯爵

Commons HttpClientを使用している場合は、nuxeo.com / blog /…に多くの関連情報があります。RFC 2616、セクション14:持続的接続をサポートしないHTTP / 1.1アプリケーションは、すべてのメッセージに「閉じる」接続オプションを含める必要があります。
Mayank Ahuja 2015

回答:


79

CLOSE_WAITプログラムがまだ実行中であり、ソケットを閉じていないことを意味します(そして、カーネルはそれが閉じるのを待っています)。に追加-pnetstatてpidを取得し、それをより強力に殺します(SIGKILL必要に応じて)。それはあなたのCLOSE_WAITソケットを取り除くはずです。pspidを見つけるために使用することもできます。

SO_REUSEADDRサーバーとTIME_WAITソケット用なので、ここでは適用されません。


2
ええと...そのプログラムが多くの接続を開く場合、プロセスをキルすることは最善ではないかもしれません。「CLOSE_WAIT」にとどまっている人のほんの一部です。その場合、プロセスを強制終了することは完全に不可能または不適切かもしれません(プログラムはまだ機能し、それらの他の接続でサービスを提供します)。保留中の接続を閉じるだけの方がはるかに適切です。しかし実際には、通常、connectinoをローカルで閉じていないのはプログラム自体です(CLOSE_WAITは、もう一方の端から「FIN」を受信したことを意味し、プログラムは接続をローカルで閉じる必要があります)。バグレポートが適切な場合があります
Olivier Dulac 2017

40

クリストクラークによって説明されているように。

CLOSE_WAITは、接続のローカルエンドがもう一方のエンドからFINを受信したが、OSはローカルエンドのプログラムが実際に接続を閉じるのを待機していることを意味します。

問題は、ローカルマシンで実行されているプログラムがソケットを閉じていないことです。TCPチューニングの問題ではありません。プログラムが接続を開いたままにしている間、接続は(そして非常に正確に)永久にCLOSE_WAITにとどまることができます。

ローカルプログラムがソケットを閉じると、OSはFINをリモートエンドに送信できます。リモートエンドは、FINのACKを待つ間、LAST_ACKに移行します。それが受信されると、接続は終了し、接続テーブルから削除されます(終了がCLOSE_WAITの場合、TIME_WAIT状態になることはありません)。


4
ソケットを閉じる方法は??
Divyang Shah 2015

1
開いたソケットのハンドルを閉じます。使用しているプラ​​ットフォームに応じて、close()またはclosesocket()を使用します。
Remy Lebeau 2015

8

最新のTomcatサーバー(7.0.40)でも同じ問題が発生しています。数日間、1回応答しなくなります。

開いている接続を確認するには、次を使用できます。

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

この投稿で述べたように、を使用/proc/sys/net/ipv4/tcp_keepalive_timeして値を表示できます。値は秒単位のようで、デフォルトは7200(つまり、2時間)です。

それらを変更するには、を編集する必要があります/etc/sysctl.conf

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`

4
答えは紛らわしいです。応答しない状態が数日間続いたとおっしゃいましたが、その後、キープアライブ時間をわずか120秒に設定しようとしました。デフォルト値(7200秒)でも、数日は続かないはずですよね?
fanchyna 2015

8

CLOSE_WAIT接続が多すぎるということは、最初のコードに問題があることを意味しますが、これは適切な方法ではありません。

あなたはチェックアウトしたいかもしれません:https//github.com/rghose/kill-close-wait-connections

このスクリプトが行うことは、接続が待機していたACKを送信することです。

これは私のために働いたものです。


クローズウェイトソケットにactを送信します。動作しないで..動作する場合、なぜですか?
チャイナックス2015

OSはすでにFINをリモートホストに送信していると思います。リモートホストは、ソケットが予期しているACKで応答できない可能性があります。
ミラージュ2015

はい、そうです(カーネルコードから)。しかし、送信するパケットのSEQ(「10」)についても疑問がありますが、カーネルはそれをチェックしませんか?
チャイナックス2015

おそらくそうではありません。たくさんの乱数を試してみたところ、うまくいったようです。
ミラージュ2015

3

Socketクライアント側とサーバー側の両方のインスタンスが明示的にを呼び出す必要があることに注意してくださいclose()。どちらかの端だけが呼び出されたclose()場合も、ソケットはCLOSE_WAIT状態のままになります。


3

ssコマンドでソケットを強制的に閉じることができます。インクルードssコマンドは、ソケット統計をダンプするために使用されるツールであり、netstatと同様の方法で(より単純で高速ですが)情報を表示します。

CLOSE_WAIT状態のソケットを強制終了するには、これを(rootとして)実行します。

$ ss --tcp state CLOSE-WAIT --kill

1

プログラムが新しいプロセスを生成した場合、そのプロセスが開いているすべてのハンドルを継承する可能性があることにも注意してください。独自のプログラムが終了した後でも、それらの継承されたハンドルは、孤立した子プロセスを介して存続できます。また、netstatでは必ずしも同じように表示されるとは限りません。しかし、それでも、この子プロセスが動作している間、ソケットはCLOSE_WAITでハングします。

ADBを実行している場合がありました。ADB自体は、サーバープロセスがまだ実行されていない場合、サーバープロセスを生成します。これは最初はすべてのハンドルを継承していましたが、調査中にハンドルを所有しているとは表示されませんでした(macOSとWindowsの両方に同じことが当てはまりました。Linuxについてはよくわかりません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.