WebSocket心跳重连讲解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebSocket心跳重连讲解相关的知识,希望对你有一定的参考价值。
参考技术A 最近在开发小程序用到了WebSocket,小程序提供了相应的原生API,与H5的API使用方式上有一些区别,所以流行的H5的一些成熟的类库使用起来有些困难,而原生API又存在一些缺陷,所以就自己实现了一套心跳重连机制。惯例,先简单介绍一下Websocket。
HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
所以当我们想服务器主动给客户端发送消息,HTTP是做不到的,我们只能使用轮询或者长轮询来实现类似的功能,这样的方式效率低并且浪费资源,为了解决这样的问题,WebSocket诞生了。
把你给懒得!自己官网看去!
在使用原生WebSocket的时候,我们经常会感觉不太稳定,服务端发送的消息有时候客户端接收不到,或者是客户端发送的消息服务端接收不到,虽然WebSocket也提供了onError和onClose的方法,但是经常会有各种未知情况导致断开连接而并不触发Error或Close事件。这样就导致实际连接已经断开了,而客户端和服务端却不知道,还在傻傻的等着消息来。
所以我们要解决的问题就很清晰了:
保证连接状态,连接断开时让客户端与服务端都能知道,进而重连。
页面载入后,我们连接socket先
然后调用initEventHandle来绑定各种各样的事件
这个先放在这我们一会往里填东西
我们设置一个锁和最大的重连次数,避免出现无限重连的情况,为了不给服务器太大的压力我这里设置的是5秒重试一次,最多请求12次。
改造一下initEventHandle这样我们就可以实现一般的触发Error的断线重连。
先撸为敬
心跳对象内timeout为每10秒发一次心跳,timeoutObj、serverTimeoutObj是清除定时器用的对象,reset方法重置定时器,start发送心跳。
继续改造我们的initEventHandle
uniapp即时聊天 websocket封装(建立连接断线重连心跳机制主动关闭)
- 使用 SocketTask 的方式去管理 webSocket 链接,每一条链路的生命周期都更加可控
- 可实现主动建立连接、心跳防断线机制、断线主动重连、提供主动断开的方法
一、如何使用 (uniapp Vue3)
<template>
// ...
</template>
<script setup>
import WS from './websocket'
import onLoad, onUnload from '@dcloudio/uni-app'
// 进入聊天页面初始化
let ws = null
onLoad((options) =>
ws = new WS(
// 连接websocket所需参数
data: userId: options.userId ,
// 首次连接成功之后,断线重新连接后也会触发(防止断线期间对方发送消息未接收到)
onConnected: () =>
// toDo
// 一般用于请求历史消息列表 getHistoryList()
,
// 监听接收到服务器消息
onMessage: (data) =>
// toDo
// 一般用于将最新的一条消息展示在页面上
)
)
// 发送消息
function sendMsg()
uni.request(
url: '后端url',
data: ...,
success: () =>
// 发送成功后,上方onMessage会接收到最新消息
)
// 页面销毁,断开websocket
onUnload(() =>
// 主动关闭websocket
ws.close()
)
</script>
二、websocket类代码
// 心跳间隔、重连websocket间隔,5秒
const interval = 5000
// 重连最大次数
const maxReconnectMaxTime = 5
export default class WS
constructor(options)
// 配置
this.options = options
// WS实例
this.socketTask = null
// 连接中
// 是否是正常关闭
this.normalClose = false
// 重新连接次数
this.reconnectTime = 1
// 重新连接Timer
this.reconnectTimer = null
// 心跳Timer
this.heartTimer = null
// 发起连接
this.initWS()
// 关闭WS
this.close = () =>
this.normalClose = true
this.socketTask.close()
clearInterval(this.heartTimer)
initWS()
// this.options.data 连接websocket所需参数
const url = 'wss://后端url' + this.options.data.userId
this.socketTask = uni.connectSocket( url, success() )
// 监听WS
this.watchWS()
watchWS()
// 监听 WebSocket 连接打开事件
this.socketTask.onOpen(() =>
console('websocket连接成功!')
// 连接成功
this.options.onConnected()
// 重置连接次数
this.reconnectTime = 1
// 发送心跳
this.onHeartBeat()
// 监听消息
this.onMessage()
// 关闭Toast
uni.hideLoading()
)
// 监听websocket 错误
this.socketTask.onError((res) =>
this.socketTask.close()
this.onDisconnected(res)
)
// 监听 WebSocket 连接关闭事件
this.socketTask.onClose((res) =>
// 非正常关闭
if (!this.normalClose)
this.onDisconnected(res)
)
// 监听消息
onMessage()
// 监听websocket 收到消息
this.socketTask.onMessage((res) =>
//收到消息
if (res.data)
this.options.onMessage(JSON.parse(res.data))
else
console('未监听到消息:原因:', JSON.stringify(res))
)
// 断开连接
onDisconnected(res)
console('websocket断开连接,原因:', JSON.stringify(res))
// 关闭心跳
clearTimeout(this.heartTimer)
// 全局Toast提示,防止用户继续发送
uni.showLoading( title: '消息收取中…' )
// 尝试重新连接
this.onReconnect()
// 断线重连
onReconnect()
clearTimeout(this.reconnectTimer)
if (this.reconnectTime < maxReconnectMaxTime)
this.reconnectTimer = setTimeout(() =>
console.log(`第【$this.reconnectTime】次重新连接中……`)
this.initWS()
this.reconnectTime++
, interval)
else
uni.showModal(
title: '温馨提示',
content: '服务器开小差啦~请返回聊天列表重试',
showCancel: false,
confirmText: '我知道了',
success: () =>
uni.navigateBack()
)
/** @心跳 **/
onHeartBeat()
this.heartTimer = setInterval(() =>
this.socketTask.send(
data: `heart:$this.options.data.userId`,
success()
console.log('心跳发送成功!')
)
, interval)
以上是关于WebSocket心跳重连讲解的主要内容,如果未能解决你的问题,请参考以下文章