WebSocket 心跳檢測和重連機制

為什么會進(jìn)行心跳檢測

簡單地說是為了證明客戶端和服務(wù)器還活著。websocket 在使用過程中,如果遭遇網(wǎng)絡(luò)問題等,這個時候服務(wù)端沒有觸發(fā)onclose事件,這樣會產(chǎn)生多余的連接,并且服務(wù)端會繼續(xù)發(fā)送消息給客戶端,造成數(shù)據(jù)丟失。因此需要一種機制來檢測客戶端和服務(wù)端是否處于正常連接的狀態(tài),心跳檢測和重連截止就產(chǎn)生了。

如何進(jìn)行心跳檢測和重連

思路是

  1. 每隔一段指定的時間(計時器),向服務(wù)器發(fā)送一個數(shù)據(jù),服務(wù)器收到數(shù)據(jù)后再發(fā)送給客戶端,正常情況下客戶端通過onmessage事件是能監(jiān)聽到服務(wù)器返回的數(shù)據(jù)的,說明請求正常。
  2. 如果再這個指定時間內(nèi),客戶端沒有收到服務(wù)器端返回的響應(yīng)消息,就判定連接斷開了,使用websocket.close關(guān)閉連接。
  3. 這個關(guān)閉連接的動作可以通過onclose事件監(jiān)聽到,因此在 onclose 事件內(nèi),我們可以調(diào)用reconnect事件進(jìn)行重連操作。

具體代碼實現(xiàn)

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

    /**
     * websocket啟動
     */
    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() {
        //連接成功建立的回調(diào)方法
        websocket.onopen = function (event) {
            console.log("WebSocket:已連接");
            //心跳檢測重置
            heartCheck.reset().start();
        };

        //接收到消息的回調(diào)方法
        websocket.onmessage = function (event) {
            showNotify(event.data);
            console.log("WebSocket:收到一條消息", event.data);
            heartCheck.reset().start();
        };

        //連接發(fā)生錯誤的回調(diào)方法
        websocket.onerror = function (event) {
            console.log("WebSocket:發(fā)生錯誤");
            reconnect();
        };

        //連接關(guān)閉的回調(diào)方法
        websocket.onclose = function (event) {
            console.log("WebSocket:已關(guān)閉");
            heartCheck.reset();//心跳檢測
            reconnect();
        };

        //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時,主動去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會拋異常。
        window.onbeforeunload = function () {
            websocket.close();
        };

        //關(guān)閉連接
        function closeWebSocket() {
            websocket.close();
        }

        //發(fā)送消息
        function send(message) {
            websocket.send(message);
        }
    }

    //避免重復(fù)連接
    var lockReconnect = false, tt;

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

    /**
     * websocket心跳檢測
     */
    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 () {
                //這里發(fā)送一個心跳,后端收到后,返回一個心跳消息,
                //onmessage拿到返回的心跳就說明連接正常
                websocket.send("HeartBeat");
                console.log('ping');
                self.serverTimeoutObj = setTimeout(function () { // 如果超過一定時間還沒重置,說明后端主動斷開了
                    console.log('關(guān)閉服務(wù)');
                    websocket.close();//如果onclose會執(zhí)行reconnect,我們執(zhí)行 websocket.close()就行了.如果直接執(zhí)行 reconnect 會觸發(fā)onclose導(dǎo)致重連兩次
                }, self.timeout)
            }, this.timeout)
        }
    };
});
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢夢敢當(dāng)閱讀 9,034評論 0 50
  • Socket并非是一個協(xié)議,而是為了方便使用TCP而抽象出來的一層,是位于應(yīng)用層和傳輸控制層之間的一組接口。換句話...
    JunChow520閱讀 3,528評論 0 4
  • 什么是WebSocket呢? WebSocket是HTML5新增的一種通信協(xié)議,目標(biāo)主流的瀏覽器都支持這個協(xié)議,比...
    JunChow520閱讀 7,538評論 1 5
  • 網(wǎng)絡(luò)編程 1. 概論 建立連接:通過IP或者域名來連接兩臺設(shè)備,通過端口號找到對應(yīng)的通信程序 通信協(xié)議:要傳輸?shù)臄?shù)...
    陵無山閱讀 8,182評論 0 12
  • 初探和實現(xiàn)websocket心跳重連 心跳重連緣由 在使用websocket過程中,可能會出現(xiàn)網(wǎng)絡(luò)斷開的情況,比如...
    _雙眸閱讀 1,063評論 0 3

友情鏈接更多精彩內(nèi)容