【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 单方面释放连接
相关推荐
guodingdingh19 分钟前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯2 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育2 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵2 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影4 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Miao121315 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔5 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
CRMEB系统商城6 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience7 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu