安卓端一天建了 159 次 WebSocket 连接,160 次异常断开。主因是 5 GHz 链路重传,代码里三个小毛病把每次断线和每次回前台都放大成一条僵尸连接。
第一处:强制重连只在地址变了的时候才关旧连接,地址没变就直接新建,旧的那条留在原地。第二处:被替换掉的旧连接,客户端在每个回调第一行就 return 掉了,只是不理它,并没有关。服务端的 ping 发到旧连接上也就没人回 pong,只能等心跳超时把它踢掉。回 pong 那里另有一个小竞态:用的是「当前连接」的引用,校验和发送之间刚好发生重连,pong 会从新连接发出去。第三处:每次回到前台都无条件强制重连。
服务端也有一半:从注册表里移除连接时只删了记录,没关 socket,留下服务端看不见、客户端还以为在线的半开连接。
修法都很小:重建前先关旧的;被新连接替换的直接关掉;pong 从收到 ping 的那条连接发;已经连着就只做状态同步,不重建;服务端注销后在锁外补一次 close。