CLOSE_WAITソケット接続を削除します
1. 概要
このチュートリアルでは、CLOSE_WAITソケット接続を削除する方法を学習します。
まず、CLOSE_WAITの状態を学習します。 次に、 CLOSE_WAIT ソケット接続を使用してプロセスを強制終了することにより、ソケット接続を削除できることがわかります。 または、CLOSE_WAITソケットに関連付けられているファイル記述子を閉じて削除できることを学習します。
2. CLOSE_WAIT状態
TCPプロトコルを使用する場合、ソケットには状態が関連付けられています。 たとえば、サーバーがソケットを使用し、ポートで着信接続を待機している場合、そのソケットはLISTEN状態になります。
ssコマンドを使用してすべてのソケットとその状態を一覧表示できます。-ta オプションを追加すると、 ss はTCPソケット(
$ ss -ta
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:ssh 0.0.0.0:*
LAST-ACK 0 1 192.168.0.5:56466 217.70.190.250:https
ESTAB 0 0 192.168.0.5:51652 31.13.94.52:https
TIME-WAIT 0 0 192.168.0.5:4262 195.201.141.166:https
(...)
最初の列でソケットの状態を確認できます。
接続が確立されると、接続のどの側でも接続を終了できます。 リモート側が接続を終了すると、それ以上のデータを送受信できなくなります。 したがって、接続を閉じることしかできません。
ただし、 CLOSE_WAIT ソケットが表示される場合は、ソフトウェアのバグが原因である可能性があります。 たとえば、プロセスが応答しなくなり、リモート側が接続を閉じた場合、ソケットが閉じられることはありません。 したがって、これが発生した場合、ソケットはCLOSE_WAIT状態のままになります。
3. CLOSE_WAITソケットを使用してプロセスを見つける
grep を使用して、CLOSE_WAITソケットをフィルタリングできます。 ただし、CLOSE_WAITではなくCLOSE-WAITでフィルタリングする必要があります。 試してみよう:
$ ss -tap | grep CLOSE-WAIT
CLOSE-WAIT 1 0 127.0.0.1:9999 127.0.0.1:56990 users:(("nc",pid=23117,fd=4)
PID 23117、およびCLOSE_WAIT状態のソケットを持つncプロセスがあります。
または、 state パラメーターを使用して、TCP状態でソケットをフィルター処理することもできます。 したがって、パラメータ state CLOSE-WAIT を追加して、すべてのCLOSE_WAITソケットを一覧表示できます。 試してみよう:
$ ss -tap state CLOSE-WAIT
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
1 0 127.0.0.1:9999 127.0.0.1:56990 users:(("nc",pid=23117,fd=4))
ssコマンドが以前と同じncプロセスをリストしていることがわかります。
4. CLOSE_WAITソケット接続の削除
プロセスがわかったので、2つの方法のいずれかを使用してCLOSE_WAITソケットを削除できます。 1つの方法は、プロセスを強制終了することです。 ただし、プロセスを強制終了したくない場合もあります。 したがって、そのような場合は、ファイル記述子を閉じることを含む他の方法を使用できます。
4.1. プロセスを殺す
CLOSE_WAIT ソケットを削除する1つの方法は、プロセスを強制終了することです。 プロセスが終了すると、システムはすべてのソケットも閉じます。
kill コマンドとプロセスIDを使用して、それを強制終了できます。 デフォルトのSIGTERM信号でそれを殺そうとすることができます。 ただし、プロセスが応答しない可能性があるため、プロセスが強制終了されない場合は、SIGKILL信号で再試行できます。
kill を実行して、ncプロセスをPID23117で終了しましょう。
$ kill 23117
それでは、ソケットがまだCLOSE_WAITにあるかどうかを確認しましょう。
$ ss -tap state CLOSE-WAIT
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
1 0 127.0.0.1:9999 127.0.0.1:56990 users:(("nc",pid=23117,fd=4))
$ kill -KILL 23117
それでは、CLOSE_WAITソケットがあるかどうかをもう一度確認しましょう。
$ ss -tap state CLOSE-WAIT
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
最後に、CLOSE_WAITソケットがないことがわかります。
4.2. ファイル記述子を閉じる
CLOSE_WAIT ソケットを削除する別の方法は、関連するファイル記述子を閉じることです。 これを行うには、gdbデバッガーを使用できます。
プロセスを強制終了したくない場合は、この代替手段を使用できます。 ただし、プロセスの実行を操作し、その内部状態を変更します。 したがって、ファイル記述子を閉じた後、プロセスが誤って動作するか、通常の実行を続行するか、を終了する可能性があります。
前のセクションで、CLOSE_WAITソケットとPID23117を使用するプロセスを見つけました。 PIDの後に、ssは「fd=4」を出力します。これは、そのソケットに関連付けられているファイル記述子が番号4であることを意味します。
これで、gdbを使用してファイル記述子を閉じることができます。最初に、 -p フラグとそれに続くPIDを使用して、gdbをプロセスにアタッチできます。 次に、 gdbプロンプトでprint(int)close(FD)コマンドを実行して、ファイル記述子を閉じることができます。 FD を、[に関連付けられたファイル記述子番号に置き換える必要があります。 X193X]CLOSE_WAITソケット。 最後に、 gdb を終了し、quitコマンドを実行します。
PID 23117でプロセスに接続し、そのファイル記述子番号4を閉じましょう。
$ gdb -p 23117
GNU gdb (GDB) 11.2
Attaching to process 23117
(gdb) print (int)close(4)
$1 = 0
(gdb) quit
または、プロセスにアタッチしてFDを閉じ、ワンライナーを使用してgdbを終了することもできます。 -batchパラメーターと-exを追加します。パラメータの後に引用符で囲まれたprint(int)close(4)コマンドが続きます。 試してみよう:
$ gdb -p 23117 -batch -ex 'print (int)close(4)'
0x00007f99d1a0fb84 in select () from /lib64/libc.so.6
$1 = 0
[Inferior 1 (process 23117) detached]
ss を再実行して、CLOSE_WAITソケットがあるかどうかを確認しましょう。
$ ss -tap state CLOSE-WAIT
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
現在、CLOSE_WAITソケットがないことがわかります。
5. 結論
この記事では、CLOSE_WAITソケット接続を削除する方法を説明しました。
まず、CLOSE_WAIT状態の意味を確認しました。 次に、 CLOSE_WAIT ソケットを使用してプロセスを見つけ、それを強制終了してCLOSE_WAITソケット接続を削除できることを学びました。 最後に、 gdb を使用して、ソケットに関連付けられたファイル記述子を閉じることもできることを確認しました。