WebSocket断线重连实践解决方案

/ javascript / 没有评论 / 2837浏览

websocket断线重连实践解决方案

最近做的在线竞答的项目需要使用websocket保持实时通讯,实现同步推题多用户在线竞答。在做过的过程中发现websocket断线频率较高,通过网上查询资料了解到nginx代理的websocket转发,无消息连接会出现超时断开问题。网上资料提到解决方案两种,一种是修改nginx配置信息,第二种是websocket发送心跳包。

下面就来总结一下本次项目中实践中解决的websocket的断线 和 重连 这两个问题的解决方案。首先我们来看看websocket的断线问题处理,在说明这个问题之前先来说说websocket,WebSocket是是html5开始提供的一种在单个TCP连接上进行全双工通讯协议。WebSocket用于在Web浏览器和服务器之间进行任意的双向数据传输的一种技术。

1. 创建连接:

var ws = new websocket(url);

2. 握手成功

ws.onopen = () => {
     console.log("websocket success!");           
};

3. 监听消息推送

ws.onmessage = (message) => {
     console.log(JSON.stringify(message));           
};

4. 监听断开连接

ws.onclose = () => {
     console.log("websocket close!");           
};

5. 监听错误信息

ws.onerror= (err) => {
     console.log(JSON.stringify(err));           
};

6. 主动断开连接

ws.close();

主动断开连接,根据需要使用,基本很少用到。

7. 主动发送消息

ws.send("hello world");

针对websocket断线

我们来分析一下,

断线的可能原因1:websocket超时没有消息自动断开连接

应对措施:这时候我们就需要知道服务端设置的超时时间是多少,在小于超时时间内发送心跳包,有2中方案,一种是客户端主动发送上行心跳包,另一种方案是服务端主动发送下行心跳包。下面主要讲一下客户端也就是前端如何实现心跳包:

首先了解一下心跳包机制

心跳检测步骤:

  1. 客户端每隔一个时间间隔发生一个探测包给服务器
  2. 客户端发包时启动一个超时定时器
  3. 服务器端接收到检测包,应该回应一个包
  4. 如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
  5. 如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了

前端解决方案:

//心跳检测
var heartCheck = {
    timeout: 30000,        //30秒发一次心跳
    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("ping");
            console.log("ping!")
            self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                ws.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
            }, self.timeout)
        }, this.timeout)
    }
}

断线的可能原因2:websocket异常包括服务端出现中断,交互切屏等等客户端异常中断等等

针对这种异常的中断解决方案就是处理重连,下面我们给出的重连方案是使用js库处理:引入reconnecting-websocket.min.js,ws建立链接方法使用js库api方法:

var ws = new ReconnectingWebSocket(url);

断线重连:

reconnectSocket(){
    if ('ws' in window) {
        ws = new ReconnectingWebSocket(url);
    } else if ('MozWebSocket' in window) {
        ws = new MozWebSocket(url);
    } else {
        ws = new SockJS(url);

    }
}

断网监测支持使用js库:offline.min.js

onLineCheck(){
    Offline.check();
    console.log(Offline.state,'---Offline.state');
    console.log(this.socketStatus,'---this.socketStatus');
    if(!this.socketStatus){
        console.log('网络连接已断开!');
        if(Offline.state === 'up' && websocket.reconnectAttempts > websocket.maxReconnectInterval){
            window.location.reload();
        }
        reconnectSocket();
    }else{
        console.log('网络连接成功!');
        websocket.send("heartBeat");
    }
}

在websocket断开链接时调用网络中断监测

websocket.onclose => () {
    onLineCheck();
};

上面是实践过的解决方案,如果大家有更好的解决方案欢迎评论区分享交流。