Qodes
Qodes
发布于 2025-09-18 / 0 阅读
0
0

WebSocket

对的,你的理解没错:

如果内网 Spring Boot 作为 WebSocket 客户端 连外网的 WebSocket 服务端,那么理论上这两个进程之间会一直保持一个 TCP 长连接。

但是“理论上一直保持”≠“实际上永远不会断”。在真实环境里,WebSocket 链接可能因为很多原因断开,需要你在客户端做心跳检测 + 重连机制。

什么时候会断开?

常见原因分几类:

1.网络层原因

  • 防火墙 / NAT 超时:
    很多防火墙/NAT 对“空闲 TCP 连接”有限制,比如 60 秒/300 秒没数据就认为连接死了,直接丢弃。

  • 网络抖动 / 断网:
    内网服务器访问外网的出口网络不稳定,包丢了,连接就会断。

  • 代理/负载均衡策略:
    有些外网服务器放在云上,前面有 Nginx/ELB 等代理,它们会对长连接有限制(如 idle timeout 60s/120s)。

2.

应用层原因

  • 服务端主动关闭:
    外网 WebSocket 服务端重启、升级、超时策略(例如某些云服务默认 1 小时断一次)。

  • 客户端异常:
    内网 Spring Boot 内存溢出、进程重启、线程池阻塞等。

3.

安全层原因

  • 证书过期/错误:wss:// 握手失败。

  • token 过期:如果你用 Bearer token 做认证,token 失效时外网可能关闭连接。

如何应对?

所以几乎所有生产可用的 WebSocket 客户端都会做三件事:

  1. 心跳机制(keepalive)

    • 客户端定时发 ping(或自定义心跳包),服务端 pong 回复。

    • 典型间隔:30 秒 ~ 1 分钟。

    • 作用:防止 NAT/防火墙踢掉空闲连接 + 检测连接是否还活着。

  2. 断线重连

    • 一旦连接异常关闭,客户端进入重连流程。

    • 重连不要死循环,要指数退避(比如 1s, 2s, 4s, 8s… 上限 1min)。

    • 避免雪崩:每个实例加随机抖动(jitter)。

  3. 会话恢复

    • 断开期间外网可能有新消息没推过来。

    • 解决方案:

      • 内网重连时带上“上次处理的 messageId”,外网从这个位置继续推送(offset)。

      • 或者外网维护“未 ACK 消息队列”,客户端重连后重新补发。

实际效果

  • 在理想稳定网络环境:连接可以跑几天/几周不掉。

  • 在现实互联网环境:几小时 ~ 一天内可能就断过,需要心跳+重连。

  • 在企业内网环境:防火墙/NAT 超时是最常见原因,不加心跳基本 5~10 分钟就掉线。

✅ 总结一句:

是的,WebSocket 设计就是要保持长连接;但在实际部署中,连接一定会偶尔断掉,必须做心跳检测和断线重连,最好还要有“消息重放”机制保证数据完整性。

要不要我帮你给出一个 Spring Boot WebSocket 客户端的心跳 + 自动重连代码样例?这样你直接能在内网系统里用,不用自己踩坑。


评论