WebSocket 实时通信实战:长连接、心跳保活与断线重连
2026/9/8 19:49:03 网站建设 项目流程

WebSocket 实时通信实战:长连接、心跳保活与断线重连

前言

http请求是“一问一答”,很多场景(聊天、行情推送、设备状态同步)需要服务端主动推数据,这时候就得上WebSocket。鸿蒙提供了@ohos.net.webSocket。但“连上了”只是开始,真正的难点是长连接保活、断线重连、消息有序。本文给出一个可直接落地的封装。

问题描述

直接用webSocket常遇到:

  1. 手机锁屏/切后台几分钟后,连接悄无声息断开,收不到推送也没报错。
  2. 弱网闪断后,业务层完全不知情,状态一直“假在线”。
  3. 重连时疯狂重试,把服务端打挂(或自己被限流)。
  4. 收到消息后不知道当前属于哪个会话/请求,难以分发。

这些问题单靠on('open')/on('message')解决不了,需要一套“连接管理”策略。

细节解析

WebSocket 典型生命周期:connectopenmessage/close/error→ 可能重连。

心跳保活:TCP 连接在长时间无数据时会因 NAT/运营商超时被回收。解决方法是定时(如 30s)发一个小包(ping/pong),让链路“有动静”。服务端通常回 pong,客户端收到即认为存活。

断线重连:监听close/error,用指数退避重试(1s、2s、4s…上限如 30s),避免雪崩。重连成功后重新发送“登录/订阅”指令恢复上下文。

消息分发:建议定义统一协议{type, payload, seq},收到后按type路由,按seq去重/对齐请求。

注意权限module.json5需要ohos.permission.INTERNET;URL 必须是ws://wss://

示例代码

// ws/WsClient.etsimport{webSocket}from'@kit.NetworkKit'exportclassWsClient{privatews?:webSocket.WebSocketprivateurl:stringprivatetimer?:numberprivateclosedByUser=falseprivateretry=0onMessage?:(data:string)=>voidconstructor(url:string){this.url=url}connect(){this.closedByUser=falsethis.ws=webSocket.createWebSocket()this.ws.on('open',()=>{this.retry=0this.startHeartbeat()// 重连后恢复订阅(示例)this.send(JSON.stringify({type:'auth',token:'xxx'}))})this.ws.on('message',(data:string|ArrayBuffer)=>{consttext=typeofdata==='string'?data:''this.onMessage?.(text)})this.ws.on('close',()=>this.scheduleReconnect())this.ws.on('error',()=>this.scheduleReconnect())this.ws.connect(this.url)}privatestartHeartbeat(){this.timer=setInterval(()=>{this.ws?.send('{"type":"ping"}')},30000)asunknownasnumber}privatescheduleReconnect(){if(this.closedByUser)returnclearInterval(this.timer)constdelay=Math.min(30000,1000*2**this.retry)this.retry++setTimeout(()=>this.connect(),delay)}send(msg:string){this.ws?.send(msg)}close(){this.closedByUser=trueclearInterval(this.timer)this.ws?.close()}}

页面使用:

@Entry@Componentstruct ChatPage{privateclient=newWsClient('wss://example.com/ws')@Statelog:string=''aboutToAppear(){this.client.onMessage=(t)=>{this.log=t}this.client.connect()}aboutToDisappear(){this.client.close()}build(){Column(){Text(this.log)Button('发消息').onClick(()=>this.client.send('{"type":"chat","text":"hi"}'))}.padding(20)}}

要点:

  • close/error都触发重连,但用户主动close()要置closedByUser,避免无限重连。
  • 心跳间隔与服务端协商,过短浪费流量,过长保活失效(常见 20–30s)。
  • 指数退避上限要设,否则退避到几分钟不现实。

总结

  • 实时推送用WebSocket@ohos.net.webSocket),别用轮询浪费资源。
  • 长连接必须做心跳,否则后台被回收却无感知。
  • 断线用指数退避重连,并恢复登录/订阅上下文。
  • 消息走统一协议 + 按type分发,业务才好维护。
  • 记得INTERNET权限与wss安全连接。

把“连接管理”当成一等公民,WebSocket 才能在生产环境稳定跑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询