Preliminary exploration and implementation of websocket heartbeat reconnection

Reasons for heartbeat reconnection

During the process of using websocket, there may be a network disconnection, such as a bad signal, or the network is temporarily closed. At this time, the connection of the websocket has been disconnected,
and the browser will not execute the onclose method of the websocket. We have no way of knowing if the connection is disconnected, so we cannot reconnect.
If the websocket data is currently sent to the backend, once the request times out, onclose will be executed, and the bound reconnection operation can be performed at this time.
Therefore, the websocket heartbeat reconnection came into being.

How to implement

When websocket is instantiated, we will bind some events:
var ws = new WebSocket(url);
ws.onclose = function () {
    //something
};
ws.onerror = function () {
    //something
};

ws.onopen = function () {
   //something
};
ws.onmessage = function (event) {
   //something
}

If we want the websocket connection to be maintained, we will bind the reconnect method on close or error.
ws.onclose = function () {
    reconnect();
};
ws.onerror = function () {
    reconnect();
};

In this way, when the connection is lost under normal circumstances, the onclose method is triggered, and we can perform reconnection.

So how to realize the heartbeat reconnection in case of network disconnection?
Simple implementation:
var heartCheck = {
    timeout: 60000,//60ms
    timeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
     this.start();
    },
    start: function(){
        this.timeoutObj = setTimeout(function(){
            ws.send("HeartBeat");
        }, this.timeout)
    }
}

ws.onopen = function () {
   heartCheck.start();
};
ws.onmessage = function (event) {
    heartCheck.reset();
}

As in the above code, the reset and start methods of heartCheck are mainly used to control the timing of the heartbeat.

Under what conditions to execute the heartbeat:

when onopen is connected, we start the start timing. If onmessage obtains the message from the backend within the time frame, we reset the countdown, and it is more than After 60 seconds, perform heartbeat detection to see if the connection is disconnected. This detection time can be set by yourself according to your own situation.

Judging that the front-end ws is disconnected (the network is disconnected but not limited to the case of disconnection):

After the heartbeat detection send method is executed, if the current websocket is disconnected (or disconnected from the network), after the sending timeout, the browser's ws will automatically Trigger the onclose method, and the reconnection is also executed (the onclose method body is bound to the reconnection event). If the network is currently disconnected, the reconnection will be executed once for 2 seconds (the time is set by your own code) until the connection is successful after the network is normal. .

In this way, we judge that the heartbeat detection of the front-end actively disconnecting ws is realized. Why is it said that the front-end is actively disconnected, because the current situation is mainly judged by the events of the front-end ws, and the back-end is actively disconnected.

I wanted to test the websocket timeout, but found some new problems
  • In chrome, if the heartbeat detection, that is, after the websocket instance executes send, is not sent to another receiver within 15 seconds, onclose will be executed. Then the timeout is 15 seconds.
  • I opened Firefox again, and Firefox directly executes onclose after 7 seconds of disconnection. It means that Firefox can automatically onclose without heartbeat detection.
  • The same code, the reconnect method is executed once in chrome and twice in Firefox. Of course we bind reconnect() in several places (code logic and websocket events)

So to be on the safe side, we still add a lock to the reconnect() method to ensure that it is only executed once.

At present , different browsers have different mechanisms. Whether the browser websocket itself will execute onclose in the case of a disconnection, add After the heartbeat is reconnected, the normal triggering of onclose can be guaranteed.

Judging the backend disconnection:

If the backend disconnects ws due to some circumstances, under controllable circumstances, a disconnection message notification will be sent, and then it will be disconnected, and we will reconnect.
If the connection is disconnected due to some exceptions, we will not sense it, so if we send the heartbeat for a certain period of time, the backend neither returns a heartbeat response message, nor does the frontend receive any other messages, we can conclude The backend is actively disconnected.
It is particularly important to send a heartbeat to the backend. The backend must return the message after receiving the message, otherwise it will be determined that the backend is actively disconnected after more than 60 seconds. Modify the code again:
var heartCheck = {
    timeout: 60000,//60ms
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
     this.start();
    },
    start: function(){
        var self = this;
        this.timeoutObj = setTimeout(function(){
            ws.send("HeartBeat");
            self.serverTimeoutObj = setTimeout(function(){
                ws.close();//If onclose will execute reconnect, we can execute ws.close(). If reconnect is executed directly, it will trigger onclose and cause reconnection twice
            }, self.timeout)
        }, this.timeout)
    },
}

ws.onopen = function () {
   heartCheck.start();
};
ws.onmessage = function (event) {
    heartCheck.reset();
}
ws.onclose = function () {
    reconnect();
};
ws.onerror = function () {
    reconnect();
};

Because at present we will keep reconnecting in this way. If it is not connected or disconnected, if there are two devices logged in at the same time and the other end will be kicked off the line, we must send a message type of kick off line. If there are different types of messages, the reconnect will not be executed after the logical judgment, otherwise there will be an infinite loop of squeezing each other off the line.

Organized a simple demo to github, click to view https://github.com/iaiai/websocket

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326572279&siteId=291194637