技术饭

websocket 心跳包保持连接和关闭重连

copylian    0 评论    8032 浏览    2021.04.02

整体架构:

前端:浏览器websocket

后端:nginx+tomcat

nginx 设置(超过 90s 没有传输数据将关闭连接):

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

proxy_connect_timeout      5;

proxy_send_timeout         90;#超过这个时间服务器将关闭连接

proxy_read_timeout         90;#超过这个时间服务器将关闭连接

1. 初始化 websocket

只考虑浏览器原生支持 websocket 的情况。

var websocket;

var host= window.location.host;

if ('WebSocket' in window) {

    websocket = new WebSocket("ws://"+host+"/ws/user-channel");

} else if ('MozWebSocket' in window) {

    websocket = new MozWebSocket("ws://"+host+"/ws/user-channel");

} else {

    // websocket = new SockJS("http://localhost:8080/sockjs/user-channel");

    websocket = null;

}

// websocket事件

websocket.onopen = function (evnt) {

    console.log("onopen: ", evnt);

    heartCheck.start();

};

websocket.onmessage = function (evnt) {

    console.log("onmessage: ", evnt);

    heartCheck.reset();

    doSomething();// 业务逻辑

};

websocket.onerror = function (evnt) {

    console.log("onerror: ", evnt);

};

websocket.onclose = function (evnt) {

    console.log("onclose", evnt);

    if (evnt.code != 4500) {

        //4500为服务端在打开多tab时主动关闭返回的编码

        reconnect();//重连

    }

}

2. 心跳包保持连接

因为服务端在 90s 未传输数据时会主动关闭连接,所以,客户端需要定时发送数据保持连接。

发送心跳数据代码:

var heartCheck = {

    timeout: 60000,//60s

    timeoutObj: null,

    reset: function(){

        clearInterval(this.timeoutObj);

        this.start();

    },

    start: function(){

        this.timeoutObj = setInterval(function(){

            if(websocket.readyState==1){

                websocket.send("HeartBeat");

            }

        }, this.timeout)

    }

};

在 websocket onopen 事件上执行 heartCheck.start(),表示连接成功后开始发送心跳包(每隔 60s 发送一次);

在 onmessage 事件执行 heartCheck.reset() ,收到数据时,重置发送心跳定时程序。

// websocket事件

websocket.onopen = function (evnt) {

    console.log("onopen: ", evnt);
            heartCheck.start();

};

websocket.onmessage = function (evnt) {

        console.log("onmessage: ", evnt);

        heartCheck.reset();

        doSomething();// 业务逻辑

};

3. 关闭重连

特殊情况下,如网络故障,服务器故障等发生时(一般情况 onclose 事件的 evnt.code=1006),需要重连。

其中 evnt.code = 4500 是我在服务端主动关闭连接时(如打开多个 tab,需要把之前 tab 的 websocket 关闭)返回的代码,此种情况下,不需要重连。

websocket.onclose = function (evnt) {

        console.log("onclose", evnt);

        if (evnt.code != 4500) {

            //4500为服务端在打开多tab时主动关闭返回的编码

            reconnect();//重连

        }

}

参考:https://my.oschina.net/714593351/blog/1583592

案例:

function getQueryVariable(variable){

        var query = window.location.search.substring(1);

        var vars = query.split("&");

        for (var i=0;i<vars.length;i++) {

            var pair = vars[i].split("=");

            if(pair[0] == variable){

                return pair[1];

                }

        }

        return 0;

}

//心跳

var heartCheck = {

        timeout: 55000,//60s

        timeoutObj: null,

        reset: function(){

            clearInterval(this.timeoutObj);

            this.start();

        },

        start: function(){

        this.timeoutObj = setInterval(function(){

            if(websocket.readyState==1){

                websocket.send("HeartBeat");

            }

        }, this.timeout)

    }

};

//全局监听

var websocket = new WebSocket("wss://apitestaa.piao-duodbbuo.com/wss2?hudong_id="+getQueryVariable("hudong_id")+"&source=daping");

websocket.onopen = function(){

        console.log("websocket open");

        heartCheck.start();

}

websocket.onclose = function(){

        console.log('websocket close');

        if (evnt.code != 4500) {

            //4500为服务端在打开多tab时主动关闭返回的编码

            reconnect();//重连

        }

}

websocket.onmessage = function(e){

    console.log(e.data);

    heartCheck.reset();

 }

$(function(){

    $('#number').html(getQueryVariable("hudong_id"));

})

心跳请求与返回:

1617349897(1).png

只袄早~~~
感谢你的支持,我会继续努力!
扫码打赏,感谢您的支持!

文明上网理性发言!

  • 还没有评论,沙发等你来抢