1. 概要

このチュートリアルでは、CLOSE_WAITソケット接続を削除する方法を学習します。

まず、CLOSE_WAITの状態を学習します。 次に、 CLOSE_WAIT ソケット接続を使用してプロセスを強制終了することにより、ソケット接続を削除できることがわかります。 または、CLOSE_WAITソケットに関連付けられているファイル記述子を閉じて削除できることを学習します。

2. CLOSE_WAIT状態

TCPプロトコルを使用する場合、ソケットには状態が関連付けられています。 たとえば、サーバーがソケットを使用し、ポートで着信接続を待機している場合、そのソケットはLISTEN状態になります。

ssコマンドを使用してすべてのソケットとその状態を一覧表示できます。-ta オプションを追加すると、 ss はTCPソケット( t [ X148X]オプション)任意の状態( a オプション)。 結果を見てみましょう:

$ 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 状態は、リモート側でソケットが閉じられており、システムがローカル側でソケットが閉じられるのを待機していることを意味します。

次に、CLOSE_WAITソケット接続を削除する唯一の方法は、それを閉じることです。 通常、プロセスはリモート側が接続を閉じるタイミングを認識し、ローカルプロセスが接続を閉じます。 これは正常な動作であるため、CLOSE_WAITソケットが表示されることはまれです。

ただし、 CLOSE_WAIT ソケットが表示される場合は、ソフトウェアのバグが原因である可能性があります。 たとえば、プロセスが応答しなくなり、リモート側が接続を閉じた場合、ソケットが閉じられることはありません。 したがって、これが発生した場合、ソケットはCLOSE_WAIT状態のままになります。

3. CLOSE_WAITソケットを使用してプロセスを見つける

まず、CLOSE_WAITソケットを使用してプロセスを見つける必要があります。 -tapフラグを指定してssコマンドを使用すると、各ソケットに関連付けられているプロセスを確認できます。 The p フラグが伝えます ss 各ソケットのプロセス情報を印刷します。

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))

おそらくncプロセスが応答しないために、ソケットがまだそこにあることがわかります。 それでは、SIGKILLシグナルを試して、強制的に終了させましょう。

$ 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 を使用して、ソケットに関連付けられたファイル記述子を閉じることもできることを確認しました。