【Java EE】 TCP—异常情况处理

异常情况处理

异常情况处理

进程崩溃

当进程崩溃时,操作系统会立即回收该进程占用的所有资源,包括已打开的文件描述符。对于 TCP socket,内核会代替进程完成剩下的工作 :自动调用 close,触发标准的 四次挥手 流程。

之所以能正常挥手,是因为 TCP 控制块是内核管理的,并不随进程消失而消失。只要内核还在运行,连接状态机就可以继续运转,完成 FIN 报文的发送与确认。
进程B(正常) 操作系统内核(A侧) 进程A(崩溃) 进程B(正常) 操作系统内核(A侧) 进程A(崩溃) 内核代劳,完成标准四次挥手,连接正常释放 进程崩溃,socket 被回收 FIN (A 主动关闭) ACK FIN (B 主动关闭) ACK

关键点 :进程崩溃与主动调用 exit 或 close 没有本质区别。只要主机未断电、内核仍在运行,TCP 就能优雅关闭。

正常关机

正常关机时,操作系统会向所有用户进程发送终止信号(如 SIGTERM),进程有机会在退出前调用 close 发出 FIN,尝试完成四次挥手。然而实际情况往往是这样:

  1. A 发出 FIN,B 回复 ACK,A 进入 FIN_WAIT_2 状态,等待 B 的 FIN。
  2. 此时若 A 的系统关机速度较快,在内核完全停止网络子系统之前,B 才发出自己的 FIN。
  3. A 的内核已经无法再处理这个 FIN,也就不会回复最后的 ACK。

B 侧因收不到 ACK,会不断重传 FIN。当重传次数耗尽后,B 判定连接失效,发送 RST 并释放资源。
主机B 主机A(正常关机) 主机B 主机A(正常关机) 进入 FIN_WAIT_2,等待 B 的 FIN A 关机,网络栈停止 无响应(内核已停止处理报文) loop 重传多次 超时,发送 RST 并释放连接 FIN(A发起挥手) ACK FIN(B 也准备关闭) FIN

所以正常关机不一定能完整完成四次挥手,最终往往仍是超时加 RST 收场,除非 B 的 FIN 在 A 关机前就到达并完成确认。

主机突然掉电

突然掉电比正常关机更恶劣,主机没有任何机会发出 FIN 报文。对端 B 完全不知道 A 已经消失,仍认为连接处于 ESTABLISHED 状态。

若 B 向 A 发送数据,这些数据均得不到 ACK,触发 TCP 超时重传机制:

  • B 的重传定时器不断超时,采用指数退避策略重传数据。
  • 达到系统设定的重传次数上限(如 tcp_retries2)后,TCP 协议栈认为连接不可达。
  • 此时 B 会发送 RST(复位报文段)(如果网络路径上对方真的可达),并强制关闭本端连接,释放资源。

主机B 主机A(突然掉电) 主机B 主机A(突然掉电) 彻底掉电,无任何应答 每次超时,重传间隔加倍 loop 超时重传,指数退- 避 重传次数耗尽,发送 RST 强制释放本端连接 发送数据(无 ACK) 重传数据 RST

如果 B 在掉电后没有数据要发送,就会一直保持僵死连接,直到触发 保活机制 。

保活机制(Keep-Alive)

TCP 协议内置了保活(Keep-Alive)机制 。当连接长时间没有数据交互时,系统会周期性地发送空 ACK 报文(心跳探测包)来确认对方是否仍在。

默认参数(各操作系统可调):

  • keepalive_time:连接空闲多久后开始探测,通常 2 小时。
  • keepalive_intvl:两次探测之间的间隔,通常 75 秒。
  • keepalive_probes:最大探测次数,通常 9 次。

流程如下:
否
是
是
否
是
否
连接空闲
超过 keepalive_time?
发送 keepalive 探测包
收到 ACK?
等待 keepalive_intvl
探测次数 < keepalive_probes?
发送 RST, 关闭连接
释放本端资源

若多次探测均无回应,则认为对端不可达,发送 RST 并单方面关闭连接,应用程序会得到"连接超时"或类似的错误。

网线断开

网线断开可以看作是双方同时遭遇对端掉电。断开瞬间,双方都无法立即感知:

  • 站在 A 视角:自己发的数据没有 ACK,B 就像掉电一样。
  • 站在 B 视角:同样的情况。

实际后果取决于是否有数据发送:

  • 有数据发送的一方:通过超时重传最终检测到异常,发送 RST 并关闭连接。
  • 没有数据发送的一方:若无上层心跳,则只能依赖 TCP 保活定时器来发现连接已死(可能等待数小时)。

因此,网线断开的最终结果通常是:

  • 正在通信的一端在几十秒到几分钟内(取决于重传配置)发现故障并释放连接;
  • 空闲的一端可能要很久才能察觉(全靠保活)。
异常场景 对端如何感知 TCP 协议行为 最终结果
进程崩溃 正常收到 FIN 内核代发 FIN,进行四次挥手 优雅释放连接
正常关机 可能收到 FIN,但最后的 ACK 常丢失 A 发 FIN,若 B 的 FIN 未及时被确认则超时 B 超时后发 RST 释放
突然掉电 数据无 ACK,触发超时重传 重传耗尽后发 RST 强制关闭,发送 RST
网线断开 类似双向掉电 有数据一侧通过超时感知,空闲侧靠保活 超时或保活失败后发 RST
长时间无数据 保活探测无响应 经过多次探测后发 RST 单方面释放连接
相关推荐
明天也要努力学习6 分钟前
深入理解 JVM 垃圾回收(GC)
java·jvm
golang学习记13 分钟前
IDEA 断点调试技巧:拖拽
java·ide·intellij-idea
Sayai14 分钟前
Flink 日志解析任务性能优化实战:正则/Grok 预编译、Guava 缓存权重陷阱与 ES 写入隔离
java·大数据·性能优化·flink·实时计算
计算机毕设定制辅导-无忧学长17 分钟前
《基于物品协同过滤的闲置书换购微信小程序设计开发》
java·vue.js·spring boot·微信小程序·uniapp·闲置书换购微信小程序·物品协同过滤算法
Best_Liu~18 分钟前
SpringBoot全局日期格式化
java·spring boot·后端
少年的范儿28 分钟前
IntelliJ IDEA 配置 JDK 21 与 Maven 教程(Windows):开发环境配置与验证
java·jdk·maven·intellij idea
RuoyiOffice30 分钟前
SpringBoot3 + openGauss:RuoYi Office 登录、流程发布与用印填报适配实战
java·数据库·spring boot·opengauss·信创
Dwzun1 小时前
基于SpringBoot3+Vue3的油莎豆种植管理系统
java·前端·vue.js·spring boot·后端·python·计算机网络
学长毕设9 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
zzu123zsw11 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp