# websocket

返回:专题

# WebSocket 心跳检测和重连机制

心跳和重连的目的用一句话概括就是客户端和服务端保证彼此还活着,避免丢包发生

通过在指定时间间隔发送心跳包来保证连接正常,如果连接出现问题,就需要手动触发 onclose 事件,这时候便可进行重连操作。因此 websocket 心跳重连就应运而生。

# 心跳重连的简单实现

  • 通过 createWebSocket 创建连接
function createWebSocket() {
  try {
    ws = new WebSocket(wsUrl);
    init();
  } catch (e) {
    console.log("catch");
    reconnect(wsUrl);
  }
}
1
2
3
4
5
6
7
8
9
  • 创建 init 方法,初始化一些监听事件,如果希望 websocket 连接一直保持, 我们会在 close 或者 error 上绑定重新连接方法。
function init() {
  ws.onclose = function() {
    console.log("链接关闭");
    reconnect(wsUrl);
  };

  ws.onerror = function() {
    console.log("发生异常了");
    reconnect(wsUrl);
  };

  ws.onopen = function() {
    //心跳检测重置
    heartCheck.start();
  };

  ws.onmessage = function(event) {
    console.log("接收到消息");
    //拿到任何消息都说明当前连接是正常的
    heartCheck.start();
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  • 重连操作,通过设置 lockReconnect 变量避免重复连接
var lockReconnect = false; //避免重复连接

function reconnect(url) {
  if (lockReconnect) {
    return;
  }
  lockReconnect = true;

  //没连接上会一直重连,设置延迟避免请求过多
  tt && clearTimeout(tt);
  tt = setTimeout(function() {
    createWebSocket(url);
    lockReconnect = false;
  }, 4000);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 心跳检测
//心跳检测

var heartCheck = {
  timeout: 3000, //每隔三秒发送心跳
  severTimeout: 5000, //服务端超时时间
  timeoutObj: null,
  serverTimeoutObj: null,

  start: function() {
    var _this = this;
    this.timeoutObj && clearTimeout(this.timeoutObj);
    this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
    this.timeoutObj = setTimeout(function() {
      //这里发送一个心跳,后端收到后,返回一个心跳消息,
      //onmessage拿到返回的心跳就说明连接正常
      ws.send("123456789"); // 心跳包
      //计算答复的超时时间
      _this.serverTimeoutObj = setTimeout(function() {
        ws.close();
      }, _this.severTimeout);
    }, this.timeout);
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 有的时候,客户端发送 3 次心跳包服务端均未回复才判定为失去连接,所以这时需要加上计数来判断。
//心跳检测

var heartCheck = {
  timeout: 3000, //每隔三秒发送心跳
  num: 3, //3次心跳均未响应重连
  timeoutObj: null,
  serverTimeoutObj: null,
  start: function() {
    var _this = this;
    var _num = this.num;
    this.timeoutObj && clearTimeout(this.timeoutObj);
    this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
    this.timeoutObj = setTimeout(function() {
      //这里发送一个心跳,后端收到后,返回一个心跳消息,
      //onmessage拿到返回的心跳就说明连接正常
      ws.send("123456789"); // 心跳包
      _num--;
      //计算答复的超时次数
      if (_num === 0) {
        ws.colse();
      }
    }, this.timeout);
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24