物理断网会立即中断TCP连接并抛出SocketException,应通过主动心跳、异常分类处理、指数退避重连、熔断机制及幂等设计实现优雅恢复。

物理断网(比如网线被拔、Wi-Fi 断开、USB 网卡被拔出)会瞬间中断 TCP 连接,底层 socket 通常抛出 SocketException(如 Connection reset、Broken pipe、Network is unreachable、No route to host 等)。这类异常不是业务错误,而是网络基础设施失效的信号——优雅处理的关键不在于“捕获后吞掉”,而在于**快速感知、安全清理、可控重连、避免雪崩**。
主动探测 + 心跳保活,别等异常发生才反应
依赖异常触发恢复是被动且滞后的。应在连接建立后启动轻量心跳机制:
- 服务端和客户端约定周期性发送小数据包(如 4 字节 ping),超时未响应即标记连接异常
- 使用
Socket.setKeepAlive(true)启用 TCP keepalive(注意:OS 层默认探测间隔长,约 2 小时;生产环境建议应用层心跳,控制在 10–30 秒级) - 心跳失败后立即关闭 socket 并触发重连逻辑,比等到下一次业务 write/read 抛异常快数秒到数十秒
区分异常类型,针对性响应
不是所有 SocketException 都该重试。需根据 message 或 errno 做细粒度判断:
-
"Connection reset"/"Broken pipe":对端已关闭或中间设备中断,应立即关闭本地 socket,进入重连流程 -
"Network is unreachable"/"No route to host":本机网络栈已检测到链路不可达(如网卡 down),暂停重连 5–30 秒,监听系统网络状态变化(如 Android 的ConnectivityManager,Linux 可监听/proc/sys/net/ipv4/conf/*/forwarding或用netlink) -
"Socket closed":属于正常关闭后误操作,无需重连,检查代码是否重复 close 或并发访问 - 其他如
"Too many open files"则属资源泄漏,需查 fd 泄露,而非网络问题
连接池与重试策略要带熔断和退避
频繁重连失败会加剧资源消耗甚至触发防火墙限流。必须限制重试行为:
- 单连接失败后采用指数退避(如 1s → 2s → 4s → 8s),最大间隔 capped(如 ≤ 60s)
- 全局维度设置“断网熔断”开关:连续 3 次重连均因网络不可达失败,暂停所有新连接尝试 2 分钟,并广播网络异常事件
- 连接池中剔除失效连接时,确保 socket 真正 close(调用
socket.close()并置 null),防止 fd 泄露;可配合PhantomReference或 try-with-resources 确保释放
应用层需容忍“连接瞬断”,设计无状态或幂等交互
即使处理再优雅,物理断网仍会导致请求丢失或超时。根本解法是让业务逻辑不依赖“长连接永续”:
- 关键操作(如支付、提交)走 HTTP/REST 或带 request-id 的消息协议,服务端支持幂等处理
- 实时通信场景(如 IM)采用“离线消息 + 消息同步”模型:客户端本地暂存未确认消息,重连后按序补发并去重
- 避免在 socket 上长期阻塞等待响应;改用异步回调 + 超时 cancel,超时后走降级逻辑(如读缓存、返回默认值)

















