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

异常情况处理

异常情况处理

进程崩溃

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

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

关键点 :进程崩溃与主动调用 exitclose 没有本质区别。只要主机未断电、内核仍在运行,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 单方面释放连接
相关推荐
lianghyan10 小时前
List.stream().min
java·开发语言
爱笑的源码基地10 小时前
小微企业ERP源码,采用SpringBoot+Vue+ElementUI+UniAPP技术架构,支持二次开发及商用授权
java·源码·二次开发·erp·源代码·mrp生产计划
happymaker062610 小时前
Spring学习日记——DAY03(yml文件)
java·spring boot·spring
凯瑟琳.奥古斯特10 小时前
操作系统核心结构解析
java·开发语言·c++·python·职场和发展
ZC跨境爬虫10 小时前
跟着 MDN 学CSS day_2:(连接样式表与选择器的实战艺术)
java·前端·css·ui·html·媒体
敖正炀11 小时前
AQS-钩子方法
java
郭郭的柳柳在学FPGA11 小时前
千兆以太网@——帧格式
java·开发语言·网络