我有一个问题,我正在尝试解决以下问题:大量本地端口转发使套接字陷入 CLOSE_WAIT,而大量远程端口转发使套接字陷入 FIN_WAIT2。
目前我不知道为什么会发生这种情况。似乎是 ssh 中的错误(在 SuSE11 R4 上运行 OpenSSH_6.6.1p1、OpenSSL 0.9.8j-fips 07 Jan 2009)。但是,我想模拟这个,以便我可以编写一个套接字粉碎程序。
我尝试编写打开套接字并死掉的Python脚本,我尝试在线程中打开它们并杀死调用应用程序。我尝试过建立 MySQL 连接并让它们悬空(因为这是导致 CLOSE_WAIT 的原因,但我无法复制它)我可以尝试 1000 种其他方法,但没有一种可能会导致这种情况发生。启动挂起连接的两个应用程序都是闭源的:((一个是 Science Logic 数据库连接,另一个是来自 Cisco CSPC 盒的某些专有连接)
那么我需要做什么才能使套接字陷入 CLOSE_WAIT 状态,以及如何使套接字陷入 FIN_WAIT2 状态?
答案1
当对等系统(进程)关闭其 TCP 连接一侧时,会发生 CLOSE-WAIT,这已被本地操作系统检测到并传输到本地进程,但本地进程尚未通过关闭其一侧的 TCP 连接来确认这一点TCP 连接。当应用程序繁忙、有错误使其“忘记”关闭其某些套接字或挂起时(因此无法进一步关闭),这通常会变得可见。同时远端会有一个相应的FIN-WAIT-2,但是这个FIN-WAIT-2最终会过期。
它可以通过本地侦听和分叉socat
进程来重现,该进程将向每个分叉子socat
进程发送 STOP 信号以“挂起”它,以及 1 秒后放弃的远程连接(也可以通过命令完成socat
):
本地将立即停止自身,保证 CLOSE-WAIT 状态,因为它无法关闭其一侧的 TCP 连接:
socat tcp4-listen:5555,reuseaddr,fork system:'kill -STOP $SOCAT_PID'
对于每个收到的连接,
socat
子进程都会被分叉,并且本身会分叉一个 shell,该 shell 将立即停止该socat
子进程(使用继承变量$SOCAT_PID
),防止它(检测远程端已关闭并)关闭 TCP 连接的其端。远程(或者在本例中也是本地的,以保持简单)将在 1 秒不活动后放弃,并沿着对等方的 CLOSE-WAIT 获取关联的 FIN-WAIT-2 状态:
for i in $(seq 1 5); do socat -T 1 -u tcp4:127.0.0.1:5555 -; echo $i; done
上述循环完成后的示例结果:
$ ss -tn sport == 5555 or dport == 5555
State Recv-Q Send-Q Local Address:Port Peer Address:Port
FIN-WAIT-2 0 0 127.0.0.1:33836 127.0.0.1:5555
FIN-WAIT-2 0 0 127.0.0.1:33846 127.0.0.1:5555
FIN-WAIT-2 0 0 127.0.0.1:33842 127.0.0.1:5555
CLOSE-WAIT 1 0 127.0.0.1:5555 127.0.0.1:33840
CLOSE-WAIT 1 0 127.0.0.1:5555 127.0.0.1:33836
CLOSE-WAIT 1 0 127.0.0.1:5555 127.0.0.1:33842
FIN-WAIT-2 0 0 127.0.0.1:33840 127.0.0.1:5555
CLOSE-WAIT 1 0 127.0.0.1:5555 127.0.0.1:33846
CLOSE-WAIT 1 0 127.0.0.1:5555 127.0.0.1:33834
FIN-WAIT-2 0 0 127.0.0.1:33834 127.0.0.1:5555
FIN-WAIT-2 最终会过期,但只要(已停止的)进程存在,CLOSE-WAIT 就会一直存在。打断主要的聆听socat
会杀死它的孩子并清理一切。