websocket 入门只需五分钟

导读:前后端实时通信常用的一种方式。
websocket 是一种采用socket 通信的连接,而不是http协议所以不受浏览器SOP的限制,是一种支持跨域访问的协议,客户端可以与任意服务器通信。

1、简单入门

1.1 初始化websocket

   initWebsockt() {
      if (typeof WebSocket === 'undefined') {
        console.log('您的浏览器不支持WebSocket')
        return
      } else {
        // 建立连接
        this.websocket = new WebSocket(this.url)
        // 连接成功
        this.websocket.onopen = this.onOpen
        // 客户端接收服务端返回的数据
        this.websocket.onmessage = this.onMessage
        // 发生错误时
        this.websocket.onerror = this.onError
        // 关闭连接时
        this.websocket.onclose = this.onClose
      }
    },

1.2 定义事件处理函数

    // 连接成功事件
    onOpen() { },
    
    // 接收数据
    onMessage(data) {
      console.log(JSON.parse(data))
      // todo 处理数据
    },

    // 连接出错事件
    onError() {
      this.reconnect()
    },

    // 连接关闭事件
    onClose() {
      this.reconnect()
    },

    // 重连
    reconnect() {
      setTimeout(() => {
        // 建立新连接
        this.initWebsockt()
      }, 5000)
    },

2、进阶 _ 断开重连(心跳检测机制)

为了实现客户端与服务器之间实时通信,就需要两端一直保持TCP长连接不能断开;在使用过程中发现隔一段时间不操作后会自动断开(使用Nginx代理websocket的场景下,Nginx有超时时间,当检测到一段时间没有数据传输后会自动断开)

然而在有些场景下确实存在长时间没有数据往来,但是需要保持连接确保即时通信的情况。解决方法如下:

  • Nginx设置超时时间长一些,(服务器端设置,此方法治标不治本)
  • 心跳机制

客户端 -> 服务端:ping
服务端 -> 客户端:pong

2.1 心跳机制

data:部分数据初始化
// heartbeat 心跳
 heartbeat: {
        interval: 30 * 1000, // 心跳间隔时间
        timeout: 10 * 1000, // 响应超时时间
        clientPingTimer: null, // 延时发送心跳的定时器
        servePongTimer: null, // 接收心跳响应的定时器
      },
核心代码:startHeartbeat
startHeartbeat() {
      const webSocket = this.webSocket
      const heartbeat = this.heartbeat
      // 重置心跳定时器
      this.clearTimeoutObj(heartbeat)
      // 等待发送心跳包
      heartbeat.clientPingTimer = setTimeout(() => {
        // 如果连接正常
        if (webSocket.readyState === 1) {
          // 发送ping,等待响应 pong
          webSocket.send('ping')
          // 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
          heartbeat.servePongTimer = setTimeout(() => {
            webSocket.close()
          }, heartbeat.timeout)
        } else {
          // 否则重连
          this.reconnect()
        }
      }, heartbeat.interval)
    },
    //  清空定时器
    clearTimeoutObj: function (heartbeat) {
      heartbeat.clientPingTimer && clearTimeout(heartbeat.clientPingTimer)
      heartbeat.servePongTimer && clearTimeout(heartbeat.servePongTimer)
    },

核心代码:调用发送心跳包

连接成功事件

    onOpen() {
      // 开启心跳
      this.startHeartbeat()
      // 重置 重连次数0
      this.reconnectTimes = 0
    },

接收数据事件

 onMessage(res) {
      // 心跳
      this.startHeartbeat()
      const data = res.data
      // 心跳响应数据pong不处理
      if (data.indexOf('pong') !== -1) {
        return
      }
      // todo 处理数据,展现数据
    },

2.2 持续优化-设置最大连接数

maxReconnect: 10, // 最大重连数
reconnectTimes: 0, // 重连次数

2.3 持续优化-重连锁

isLock: false, // 加锁,避免套娃(重连过程中再重连)

2.4 持续优化-重连

    reconnect() {
      // +++建立连接中,锁了
      if (this.isLock) {
        return
      }
      // +++超出最大连接次数
      if (this.reconnectTimes > this.maxReconnect) {
        return
      }
      this.isLock = true // +++
      setTimeout(() => {
        // +++重连次数 +1
        this.reconnectTimes++
        // 建立新连接
        this.initWebsockt()
        this.isLock = false // +++
      }, 5000)
    },

3、 思考

为什么ws有监听断开onclose,在断开里面有重连reconnect;还心跳检测呢? 有一些情况如网络断开不会被onclose监听到,有心跳检测会使连接一直保活,从而避免websocket的断开造成数据丢失。

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值