关于FIN_WAIT2
前些天,有朋友问我关于 FIN_WAIT2 的问题:如果主动关闭的一方在进入 FIN_WAIT2 状态后没有收到被动关闭的一方发送的 FIN 包,那么会怎样?
让我们热热身,通过一张旧图来回忆一下 TCP 关闭连接时的情况:
TCP Close
按照正常的状态迁移路径,当 FIN_WAIT2 收到 FIN 包后会迁移到 TIME_WAIT 状态。如果没有收到 FIN 包,那么连接状态会如何迁移,我们不妨测试一下:
#!/usr/bin/env python
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 1234))
s.listen(1)
c, _ = s.accept()
time.sleep(1000)
c.close()
如上是用 Python 实现的一个简单的 server 演示代码,需要注意的是我在 close 前设置了一个巨大的延迟时间,从而达到拖延服务端发出 FIN 包的目的。与之相对应的我们再实现一个简单的 client 演示代码,它没什么可说的,就是连上后直接关闭:
#!/usr/bin/env python
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 1234))
s.close()
测试的时候先启动服务端监听 1234 端口,再启动客户端连接 1234 端口,为了确认整个过程是否符合我们的预期,可以使用 tcpdump 监听通讯过程:
tcpdump -t -nn -i any port 1234
如图可见:在三次握手之后,客户端关闭了连接,服务端确认后没有发出 FIN 包,所以整个过程符合我们的预期,同时为了判断 FIN_WAIT2 存在了多久,写了如下代码:
shell> while sleep 1; do
netstat -ant | grep FIN_WAIT2 | while read content; do
echo -n $(date +"%T") ""
echo $content
done
done
监控发现,在本例中 FIN_WAIT2 存在的时间大约是一分钟左右:
FIN_WAIT2 存在的时间
实际上此时间是「net.ipv4.tcp_fin_timeout」控制的,不过在测试中发现,FIN_WAIT2 存在的时间并不是精确的等于 tcp_fin_timeout 的设置,存在一定的偏差。此外,需要说明的是在 tcp_fin_timeout 后,FIN_WAIT2 并没有迁移到 TIME_WAIT,而是直接关闭了。
关于 tcp_fin_timeout 的介绍,可以参考内核的说明:
The length of time an orphaned (no longer referenced by any application) connection will remain in the FIN_WAIT_2 state before it is aborted at the local end. While a perfectly valid “receive only” state for an un-orphaned connection, an orphaned connection in FIN_WAIT_2 state could otherwise wait forever for the remote to close its end of the connection. Cf. tcp_max_orphans Default: 60 seconds
介绍中提到了 orphan 的概念,指的是当一个 socket 不再被任何应用引用时,它便成为了一个孤儿,而 tcp_fin_timeout 限定了成为孤儿的 FIN_WAIT2 所能存活的时间。
注:orphan 太多的话会:The “Out of socket memory” error。
或许有人会问:如果 FIN_WAIT2 没有成为孤儿,那么会如何:
#!/usr/bin/env python
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 1234))
s.shutdown(socket.SHUT_WR)
time.sleep(1000)
s.close()
在这一版的 client 代码中,我们没有直接 close 连接,而是通过 shutdown 来关闭,此时客户端同样会发送 FIN 包,但是并没有释放连接,所以本例中的 FIN_WAIT2 和上例中的 FIN_WAIT2 不同,其并不会成为孤儿。通过测试发现,此时 tcp_fin_timeout 将失效,而 本例中的 FIN_WAIT2 会一直存在,直到客户端 close 连接或者退出。
实际上,同其它 TCP 状态相比,通常 FIN_WAIT2 并不会给你添什么麻烦。如果你统计服务器上的 TCP 状态,你会发现它们多数时候都很少,如果不是,那么一定是应用层面上出了问题。至于 tcp_fin_timeout,我并不建议大家把它设置得太小,因为如上所说,正常情况下,TCP 连接并不会在 FIN_WAIT2 状态上停留太久,假设真的出现 FIN 包丢失之类的情况,那么给 FIN_WAIT2 状态一个合理的存在周期是必要的,毕竟丢失的 FIN 包可能会重传,在这一点上和 TIME_WAIT 为什么要存在 2MSL 是同样的原因。既然 TIME_WAIT 缺省存在 60 秒,那么 tcp_fin_timeout 缺省设置为 60 同样是一个合理的选择。
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击