云计算百科
云计算领域专业知识百科平台

WebSocket 假死与断连的长连接保活与重连机制

在开发即时通讯模块时,最让人抓狂的不是消息收发写错,而是网络稍微一波动,比如从 Wi-Fi 切到 5G,或者进入电梯再出来,WebSocket 就彻底没声了。表面上看连接还在,实际上底层早就断了,这就是典型的“假死”。为了解决这个问题,这周我对 @ohos.net.webSocket 的封装进行了彻底的重构。

基础连接与心跳包的设计

原生 API 的使用非常简单,但如果没有心跳机制,连接注定短命。

import webSocket from '@ohos.net.webSocket';

let ws = webSocket.createWebSocket();

ws.on('open', () => {
console.info('连接已建立');
startHeartbeat();
});

ws.on('message', (err, value) => {
// 收到业务消息,重置心跳
resetHeartbeat();
});

注意:很多开发者会在 open 回调里疯狂地发送积压的离线消息,这是极其危险的操作。在弱网环境下,大量的并发发送会导致底层缓冲区阻塞,直接引发连接超时断开。必须加入发送队列,控制并发。

指数退避重连算法

当连接因网络原因断开时,最忌讳的就是写一个死循环,每秒疯狂发起重连。这会把手机电量瞬间抽干,甚至被系统判定为恶意应用。

我们采用了经典的“指数退避(Exponential Backoff)”算法,并加入随机因子,防止多台设备同时恢复网络导致的服务器雪崩。

let reconnectAttempts = 0; const MAX_RECONNECT = 10; function reconnect() { if (reconnectAttempts >= MAX_RECONNECT) { // 警示:达到上限,必须给用户 UI 提示,切勿无限重试 showNetworkErrorToast(); return; } // 1.5 的指数增长,加上 0-1000ms 的随机抖动 const delay = Math.min(30000, Math.pow(1.5, reconnectAttempts) * 1000) + Math.random() * 1000; setTimeout(() => { reconnectAttempts++; ws.connect(url); // 重新发起连接 }, delay); }

结合系统网络状态监听

依赖 Socket 自身的报错是被动的,最优雅的方案是主动监听系统的网络状态。当系统网络完全不可用时,直接挂起重连逻辑;网络一恢复,立刻触发。

import connection from '@ohos.net.connection'; const netConnection = connection.createNetConnection(); netConnection.on('netAvailable', (data) => { console.info('网络已恢复,强制重连'); reconnectAttempts = 0; // 重置重试次数 if (ws) { ws.close(); // 彻底关掉旧连接 ws = webSocket.createWebSocket(); ws.connect(url); } });

这能解决一个极其隐蔽的场景:用户在没有信号的电梯里待了十分钟,此时你发起的任何重连都会瞬间失败并消耗重试次数。只有依靠系统级回调,才能做到真正的“秒恢复”。

后台保活的取舍

用户切换到桌面,WebSocket 会逐渐被系统冻结。要保持后台收消息,必须申请长时任务。但注意,系统允许的 BackgroundMode 里并没有专门针对 WebSocket 的,如果强行用其他模式(如 dataTransfer)保活,极易在提审时被拒。

目前的合规解法是:后台立即断开 WebSocket,依靠华为的 Push Kit 推送来唤醒应用,等用户切回前台时,再用 netAvailable 的逻辑瞬间重连。

使用抓包工具(如 Charles),限制你的手机网络带宽,并模拟 90% 的丢包率。在这个极端弱网环境下,测试你的重连机制。如果你能保证在恢复网络后的 3 秒内重新连上,且没有引发内存溢出,这套长连接才算及格。

赞(0)
未经允许不得转载:网硕互联帮助中心 » WebSocket 假死与断连的长连接保活与重连机制
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!