websocket重连机制实现

弱网环境或者网络暂时断连的情况下,我们需要一套稳定的重连机制来保证在网络不稳定的时候,客户端和服务端能够重连,继续通信。本文将会针对websocket协议的重连机制进行详细描述。

思路

在实例化websocket后,我们会定义好各个回调事件需要执行的函数

var ws = new WebSocket(url);
ws.onclose = function () {
    //连接关闭
};
ws.onerror = function () {
    //连接报错
};
ws.onopen = function () {
    //连接成功
};
ws.onmessage = function (event) {
    //收到数据
}

在弱网环境下,发送消息无法抵达接收端;抑或,断网到浏览器约定时限等一些异常情况都会触发onclose和onerror,所以理论上,我们只要在onclose和onerror时,重新创建长连接就可以。

实现

根据上面的简单思路,代码如下:

var ws = new WebSocket(url);
ws.onclose = function () {
  reconnect()
};
ws.onerror = function () {
  reconnect()
};

function reconnect(url) {
    setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
      var ws = new WebSocket(url);
      ws.onclose = function () {
        reconnect()
      };
      ws.onerror = function () {
        reconnect()
      };
    }, 2000);
}

稍微抽取再丰富下,createWebSocket来创建websocket实例,initEventHandle来绑定各回调函数:

var ws = new WebSocket(url);
ws.onclose = function () {
  reconnect()
};
ws.onerror = function () {
  reconnect()
};

// 重连
function reconnect(url) {
    setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
      createWebSocket(url);
    }, 2000);
}

// 实例websocket
function createWebSocket(url) {
    try {
        if ('WebSocket' in window) {
            ws = new WebSocket(url);
        } else if ('MozWebSocket' in window) {
            ws = new MozWebSocket(url);
        } else {
            _alert("当前浏览器不支持websocket协议,建议使用现代浏览器",3000)
        }
        initEventHandle();
    } catch (e) {
        reconnect(url);
    }
}

// 初始化事件函数
function initEventHandle() {
    ws.onclose = function () {
        reconnect(wsUrl);
    };
    ws.onerror = function (err) {
        reconnect(wsUrl);
    };
}

优化

弱网、断连所导致重连都是被动的,而在一般的websocket连接中都是存在心跳机制的,客户端和服务端约定一个特定的心跳消息用于检测链路是否通信正常
我们通过心跳机制,在客户端来检测链路的正常,在约定时间间隔内收不到心跳或者其他任何通信消息时,客户端进行主动重连。
所以下面优化的,我们需要加一个心跳检测的方法:

var heartCheck = {
    timeout: heartBeatTime*1000,  //  心跳检测时长
    timeoutObj: null, // 定时变量
    reset: function () { // 重置定时
        clearTimeout(this.timeoutObj);
        return this;
    },
    start: function () { // 开启定时
        var self = this;
        this.timeoutObj = setTimeout(function () {
          // 心跳时间内收不到消息,主动触发连接关闭,开始重连
            ws.close();
        },this.timeout)
    }
}

心跳检测对象,定义了

  • timeout:心跳超时时间
  • timeoutObj:定时器变量
  • reset:重置心跳
  • start:开启心跳
    当连接成功时,开启心跳;在收到消息时,重置心跳并开启下一轮检测,所以我们只需要在onopen和onmessage中加入心跳检测就行
// 初始化事件函数
function initEventHandle() {
    ws.onclose = function () {
        reconnect(wsUrl);
    };
    ws.onerror = function (err) {
        reconnect(wsUrl);
    };
    ws.onopen = function () {
        heartCheck.reset().start();      //心跳检测重置
    };
    ws.onmessage = function (msg) {    //如果获取到消息,心跳检测重置
        heartCheck.reset().start();      //拿到任何消息都说明当前连接是正常的
        handleMsg(msg)
    };
}

同时触发多次重连的问题

在实际使用过程中,发现有些浏览器,reconnect重连会多次触发,所以需要给重连加一把锁,当一个重连正在执行的时候,无法再触发一次重连

function reconnect(url) {
    if (reconnect.lockReconnect) return;
    reconnect.lockReconnect = true;
    setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
        createWebSocket(url);
        reconnect.lockReconnect = false;
    }, 2000);
}

如果是同个浏览器中多个页面共用一个连接来进行通信,那么就需要使用浏览器缓存/数据路(localStorage/indexedDB)去加这把锁。

参考

1、MDN Websockt
2、初探和实现websocket心跳重连

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 心跳重连缘由 在使用websocket过程中,可能会出现网络断开的情况,比如信号不好,或者网络临时性关闭,这时候w...
    丸_子阅读 10,781评论 3 9
  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢梦敢当阅读 8,960评论 0 50
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,928评论 25 709
  • 这一集通篇将中华上下五千年的历史,大概过了一遍,抓了一些侧重点,主要就是讲述中华道路从古自今的历程。
    梁爽快阅读 2,723评论 0 0
  • 这几天,常常见,一些以人名命名的回忆录,真的好怕看着看着就只有回忆录了。赶早我也写写才好。但理科出生的我,很...
    面面香蛆阅读 433评论 0 0