1.心跳检测的缘由
websocket心跳检测的目的用一句话概括就是客户端和服务端保证彼此还活着,避免丢包发生.
websocket断开一般有两种情况
前端断开
在使用websocket过程中,可能会出现网络断开的情况,比如信号不好,或者网络临时关闭,这时候websocket的连接已经断开,而不同浏览器有不同的机制,触发onclose的时机也不同,并不会理想执行websocket的onclose方法,我们无法知道是否断开连接,也就无法进行重连操作。
后端断开
如果后端因为一些情况需要断开ws,在可控情况下,会下发一个断连的消息通知,之后才会断开,我们便会重连。
如果因为一些异常断开了连接,我们是不会感应到的,所以如果我们发送了心跳一定时间之后,后端既没有返回心跳响应消息,前端又没有收到任何其他消息的话,我们就能断定后端主动断开了。
因此需要一种机制来检测客户端和服务端是否处于正常连接的状态。通过在指定时间间隔发送心跳包来保证连接正常,如果连接出现问题,就需要手动触发onclose事件,这时候便可进行重连操作。因此websocket心跳重连就应运而生。
2.WebSocket 心跳检测的实现
2.1 首先通过new WebSocket 实例,来实现WebSocket 连接
//websocket启动
function startWebSocket() {
if ('WebSocket' in window)
ws = new WebSocket("${ws}/"+employess_number);
else if ('MozWebSocket' in window)
ws = new WebSocket("${ws}/"+employess_number);
//ws = new WebSocket("ws://172.40.1.21:8081/RDWebChat/websocket");
else
tishiFunction(1,"浏览器版本不支持!");
//得到消息
ws.onmessage = function(evt){
//心跳检测
// heartCheck.reset().start();
}
2.2 通过WebSocket实例上的一些方法可是实现断开重连
ws.onerror = function(evt){
// console.log(evt,'出错啦');
// wsReconnect();
}
ws.onmessage = function(evt){
// console.log(evt,'出错啦');
// wsReconnect();
}
ws.onclose = function(evt) {
// $('#denglu').html("离线");
heartCheck.reset();//心跳检测
//console.log(evt,'连接关闭了');
// wsReconnect();
};
ws.onopen = function(evt) {
//$('#denglu').html("在线");
// $('#userName').html(self);
// console.log(evt,'开始连接');
// heartCheck.reset().start();
};
2.3 WebSocket重连
//websocket重连
function wsReconnect(){
if(heartbeat){
return;
}
heartbeat = true;
setTimeout(function(){
console.log('重连中');
heartbeat = false;
startWebSocket();
},2000);
}
2.4 心跳检测
//websocket心跳检测
var heartCheck = {
timeout: 30000,
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
ws.send("HeartBeat");
console.log('心跳开始');
self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
console.log('关闭服务');
ws.close();//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout)
}, this.timeout)
}
}