WebSocket Heart Rate Detection and Reconnection Mechanism

Keywords: Programming network

Why heart rate detection

Simply to prove that the client and server are still alive.When a websocket is in use, if it encounters network problems, etc., the server does not trigger the onclose event at this time, which will result in redundant connections, and the server will continue to send messages to the client, causing data loss.Therefore, a mechanism is needed to detect whether the client and the server are connected properly, and heartbeat detection and reconnection cutoffs occur.

How to do heart rate detection and reconnection

The idea is:

  1. Every specified period of time (timer), send a data to the server, the server receives the data and then sends it to the client. Under normal circumstances, the client can listen for the data returned by the server through the onmessage event, indicating that the request is normal.
  2. If the client does not receive a response message from the server within the specified time, it decides that the connection is broken and closes it with websocket.close.
  3. This action to close the connection can be monitored by the onclose event, so within the onclose event, we can call the reconnect event to reconnect.

Specific code implementation

$(function () {
    var path = basePath;
    var jspCode = $("#userId").val();
    var websocket;
    createWebSocket();

    /**
     * websocket start-up
     */
    function createWebSocket() {
        try {
            if ('WebSocket' in window) {
                websocket = new WebSocket((path + "/wsCrm?jspCode=" + jspCode).replace("http", "ws").replace("https", "ws"));
            } else if ('MozWebSocket' in window) {
                websocket = new MozWebSocket(("ws://" + path + "/wsCrm?jspCode=" + jspCode).replace("http", "ws").replace("https", "ws"));
            } else {
                websocket = new SockJS(path + "/wsCrm/sockJs?jspCode=" + jspCode.replace("http", "ws"));
            }
            init();
        } catch (e) {
            console.log('catch' + e);
            reconnect();
        }

    }

    function init() {
        //Callback method for successful connection establishment
        websocket.onopen = function (event) {
            console.log("WebSocket:Connected");
            //Heart beat detection reset
            heartCheck.reset().start();
        };

        //Callback method to receive message
        websocket.onmessage = function (event) {
            showNotify(event.data);
            console.log("WebSocket:A message was received", event.data);
            heartCheck.reset().start();
        };

        //Callback method for connection errors
        websocket.onerror = function (event) {
            console.log("WebSocket:An error occurred");
            reconnect();
        };

        //Callback method for connection closure
        websocket.onclose = function (event) {
            console.log("WebSocket:Closed");
            heartCheck.reset();//runtastic Heart Rate PRO
            reconnect();
        };

        //Listen for window closing events. When the window closes, actively close the websocket connection to prevent the window from closing before the connection is broken. The server side throws an exception.
        window.onbeforeunload = function () {
            websocket.close();
        };

        //Close Connection
        function closeWebSocket() {
            websocket.close();
        }

        //send message
        function send(message) {
            websocket.send(message);
        }
    }

    //Avoid duplicate connections
    var lockReconnect = false, tt;

    /**
     * websocket Reconnection
     */
    function reconnect() {
        if (lockReconnect) {
            return;
        }
        lockReconnect = true;
        tt && clearTimeout(tt);
        tt = setTimeout(function () {
            console.log('Reconnecting...');
            lockReconnect = false;
            createWebSocket();
        }, 4000);
    }

    /**
     * websocket runtastic Heart Rate PRO
     */
    var heartCheck = {
        timeout: 5000,
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function () {
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function () {
            var self = this;
            this.timeoutObj && clearTimeout(this.timeoutObj);
            this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
            this.timeoutObj = setTimeout(function () {
                //This sends a heartbeat, and when the back end receives it, it returns a heartbeat message.
                //onmessage gets the returned heartbeat and the connection is OK
                websocket.send("HeartBeat");
                console.log('ping');
                self.serverTimeoutObj = setTimeout(function () { // If it hasn't been reset for more than a certain time, the backend is actively disconnected
                    console.log('Shut down services');
                    websocket.close();//If onclose executes reconnect, we just execute websocket.close().
                }, self.timeout)
            }, this.timeout)
        }
    };
});

Posted by Jay on Sat, 16 Nov 2019 03:51:32 -0800