当前位置: 首页 > news >正文

系统性能优化-7 TCP 四次挥手

关闭连接的调用函数分为两种:

  • close close 函数会让连接变为孤儿连接,此时该连接句柄已释放,发送 FIN 报文,由内核和对方进行挥手交互,因此此时即使接收方继续发送数据,应用进程也接收不到了
# 查看孤儿 socket 数
cat /proc/net/sockstat
sockets: used 133
TCP: inuse 9 orphan 0 tw 3 alloc 9 mem 1
UDP: inuse 2 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
  • shutdown shutdown 函数的不同传参允许在半关闭的连接上长时间传输数据

image-20250627133828680

主动方发送 FIN 报文,进入 FIN-WAIT1 状态,此时如果 FIN 报文丢失,会进行重发,重发次数默认为 8 次,由 tcp_orphan_retries 控制,默认值是 0,代表 8 次,如果改为 -1,代表无限制,会尽可能重试

sysctl net.ipv4.tcp_orphan_retries

如果 FIN_WAIT1 状态连接有很多,就需要考虑降低 tcp_orphan_retries 的值

但是 TCP 具有顺序发送和拥塞控制等特性,如果发送缓冲区前面一直有数据,FIN 报文是发送不出去的,同时如果对方恶意修改接收窗口为 0,FIN 也发送不出去,连接一直处于 FIN_WAIT1 状态。解决方案是修改 tcp_max_orphans,该字段定义了系统的最大孤儿连接数,当超出这个数目时,不走四次挥手而是直接发送 RST 复位报文强制关闭

sysctl net.ipv4.tcp_max_orphans

主动方发送 FIN 后,被动方回复 ACK,此时主动方进入 FIN-WAIT2 状态,如果是孤儿连接,这个阶段最多持续 tcp_fin_timeout 时间,如果收不到被动方的 FIN 报文,连接就会直接关闭。

sysctl net.ipv4.tcp_fin_timeout

此时被动方进入 CLOSE-WAIT 状态,如果进程调用 read 会返回 0,代表对方已经关闭发送通道了,开发人员可以据此调用本机的 close 函数关闭通信。

被动方发送 FIN 报文,进入 LAST-ACK 阶段,重试次数依然由 tcp_orphan_retries 控制,主动方收到 FIN 报文,进入 TIME-WAIT 状态,回复 ACK。TIME-WAIT 的存在是具有重要意义的,如果没有该阶段而直接关闭,可能很快有新的进程使用,此时被动方可能由于 ACK 丢失重发 FIN 报文,对主动方造成影响,该状态默认为 60s,是系统 2MSL 时长(MSL固定值30s,定义了一个报文在网络中的最长生存时间,即多数情况下 TTL 减到 0 流转的时间),这个数值是硬编码在内核中的,也就是说除非重新编译内核,否则没法修改它。

tcp_max_tw_buckets 可以限制 TIME-WAIT 状态的连接数量,当超出此数量时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。因此调大这个参数可以降低连接间数据错乱的概率,如果系统中并发连接很多时,可以适当调大该值。

sysctl net.ipv4.tcp_max_tw_buckets

tcp_tw_reuse 使系统可以复用 TIME-WAIT 状态的连接,作为客户端的新连接,在安全条件下使用 TIME_WAIT 状态下的端口,如果想要使其生效,还需要开启双方的 tcp_timestamps

# 0 关 1 开 
sysctl net.ipv4.tcp_tw_reusesysctl net.ipv4.tcp_timestamps

老版本的 Linux 还提供了 tcp_tw_recycle 参数,它并不要求 TIME_WAIT 状态存在 60 秒,很容易导致数据错乱,不建议设置为 1

sysctl net.ipv4.tcp_tw_recycle

如果被动方迅速调用 close 函数,那么被动方的 ACK 和 FIN 有可能在一个报文中发送,这样看起来,四次挥手会变成三次挥手,这只是一种特殊情况,不用在意。

总结一下本文提到的配置项:

  • net.ipv4.tcp_orphan_retries 关闭连接时发送 FIN 时的重试次数,主动方和被动方发生 FIN 都依赖这个值,默认为 0 代表 8 次,如果改为 -1,则无限制,会尽可能尝试。如果系统中出现大量 FIN-WAIT1 状态的连接,可以适当减小。
  • net.ipv4.tcp_max_orphans 最大的孤儿连接数,当超出这个数量时,不走挥手协议而是直接发送 RST 复位报文强制关闭。
  • net.ipv4.tcp_fin_timeout 孤儿连接在进去 FIN-WAIT2 状态后,等待对方发送 FIN 报文的最大等待时间。
  • net.ipv4.tcp_max_tw_buckets 系统允许的最大 TIMEWAIT 的连接数,如果是高并发服务,可以适当调大该值,根据 net.ipv4.ip_local_port_range 可用的端口数进行调整。
  • net.ipv4.tcp_tw_reuse 复用 TIMEWAIT 状态连接作为客户端的新连接,需要结合 net.ipv4.tcp_timestamps 一起使用
  • net.ipv4.tcp_tw_recycle TIMEWAIT 态连接的快速回收,不推荐开启。

相关文章:

  • 【请关注】制造企业机械加工数据脱敏解决方案
  • QGIS导出Shape文件
  • matplotlib 绘制热力图
  • uniapp中表格固定列(Vue)
  • 《游戏元素创世法则:从原子到虚拟生命的全链路解析》—— 网格/刚体/纹理/材质/骨骼/蒙皮/光照/渲染的深度关联指南
  • 广东广电U点-创维E900-S-海思MV310芯片-海兔线刷烧录固件包
  • 带标签的 Docker 镜像打包为 tar 文件
  • 策略模式与工厂模式的黄金组合:从设计到实战
  • C++并发编程-4.unique_lock,共享锁和递归锁
  • 关于Kotlin与Java的思考
  • 通过ETL从MySQL同步到GaussDB
  • Linux工作常用命令记录
  • Android开发获取视图组件的findViewById,kotlin-android-extensions,ViewBinding三种详解
  • PyWavelets
  • 分布式系统ID生成方案深度解析:雪花算法 vs UUID vs 其他主流方案
  • 航天VR赋能,无人机总测实验舱开启高效新篇​
  • 鸿蒙OS开发IoT控制应用:从入门到实践
  • 基于JavaWeb的校园失物招领系统设计与实现
  • 机器学习2——贝叶斯理论下
  • 概述-2-MySQL安装及启动-1-Dcoker安装MySQL