理解WebSocket心跳及重連機制
在使用websocket的過程中,有時候會遇到網絡斷開的情況,但是在網絡斷開的時候服務器端並沒有觸發onclose的事件。這樣會有:服務器會繼續向客戶端發送多餘的鏈接,並且這些數據還會丟失。所以就需要一種機制來檢測客戶端和服務端是否處於正常的鏈接狀態。因此就有了websocket的心跳了。還有心跳,說明還活着,沒有心跳說明已經掛掉了。
1. 爲什麼叫心跳包呢?
它就像心跳一樣每隔固定的時間發一次,來告訴服務器,我還活着。
2. 心跳機制是?
心跳機制是每隔一段時間會向服務器發送一個數據包,告訴服務器自己還活着,同時客戶端會確認服務器端是否還活着,如果還活着的話,就會回傳一個數據包給客戶端來確定服務器端也還活着,否則的話,有可能是網絡斷開連接了。需要重連~
那麼需要怎麼去實現它呢?如下所有代碼:
<html>
<head>
<meta charset="utf-8">
<title>WebSocket Demo</title>
</head>
<body>
<script type="text/javascript">
// var ws = new WebSocket("wss://echo.websocket.org");
/*
ws.onerror = function(e) {
console.log('已關閉');
};
ws.onopen = function(e) {
console.log('握手成功');
ws.send('123456789');
}
ws.onclose = function() {
console.log('已關閉');
}
ws.onmessage = function(e) {
console.log('收到消息');
console.log(e);
}
*/
var lockReconnect = false;//避免重複連接
var wsUrl = "wss://echo.websocket.org";
var ws;
var tt;
function createWebSocket() {
try {
ws = new WebSocket(wsUrl);
init();
} catch(e) {
console.log('catch');
reconnect(wsUrl);
}
}
function init() {
ws.onclose = function () {
console.log('鏈接關閉');
reconnect(wsUrl);
};
ws.onerror = function() {
console.log('發生異常了');
reconnect(wsUrl);
};
ws.onopen = function () {
//心跳檢測重置
heartCheck.start();
};
ws.onmessage = function (event) {
//拿到任何消息都說明當前連接是正常的
console.log('接收到消息');
heartCheck.start();
}
}
function reconnect(url) {
if(lockReconnect) {
return;
};
lockReconnect = true;
//沒連接上會一直重連,設置延遲避免請求過多
tt && clearTimeout(tt);
tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 4000);
}
//心跳檢測
var heartCheck = {
timeout: 3000,
timeoutObj: null,
serverTimeoutObj: null,
start: function(){
console.log('start');
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function(){
//這裏發送一個心跳,後端收到後,返回一個心跳消息,
console.log('55555');
ws.send("123456789");
self.serverTimeoutObj = setTimeout(function() {
console.log(111);
console.log(ws);
ws.close();
// createWebSocket();
}, self.timeout);
}, this.timeout)
}
}
createWebSocket(wsUrl);
</script>
</body>
</html>
具體的思路如下:
1. 第一步頁面初始化,先調用createWebSocket函數,目的是創建一個websocket的方法:new WebSocket(wsUrl);因此封裝成函數內如下代碼:
function createWebSocket() {
try {
ws = new WebSocket(wsUrl);
init();
} catch(e) {
console.log('catch');
reconnect(wsUrl);
}
}
2. 第二步調用init方法,該方法內把一些監聽事件封裝如下:
function init() {
ws.onclose = function () {
console.log('鏈接關閉');
reconnect(wsUrl);
};
ws.onerror = function() {
console.log('發生異常了');
reconnect(wsUrl);
};
ws.onopen = function () {
//心跳檢測重置
heartCheck.start();
};
ws.onmessage = function (event) {
//拿到任何消息都說明當前連接是正常的
console.log('接收到消息');
heartCheck.start();
}
}
3. 如上第二步,當網絡斷開的時候,會先調用onerror,onclose事件可以監聽到,會調用reconnect方法進行重連操作。正常的情況下,是先調用
onopen方法的,當接收到數據時,會被onmessage事件監聽到。
4. 重連操作 reconnect代碼如下:
var lockReconnect = false;//避免重複連接
function reconnect(url) {
if(lockReconnect) {
return;
};
lockReconnect = true;
//沒連接上會一直重連,設置延遲避免請求過多
tt && clearTimeout(tt);
tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 4000);
}
如上代碼,如果網絡斷開的話,會執行reconnect方法,使用了一個定時器,4秒後會重新創建一個新的websocket鏈接,重新調用createWebSocket函數,
重新會執行及發送數據給服務器端。
5. 最後一步就是實現心跳檢測的代碼:如下:
//心跳檢測
var heartCheck = {
timeout: 3000,
timeoutObj: null,
serverTimeoutObj: null,
start: function(){
console.log('start');
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function(){
//這裏發送一個心跳,後端收到後,返回一個心跳消息,
//onmessage拿到返回的心跳就說明連接正常
console.log('55555');
ws.send("123456789");
self.serverTimeoutObj = setTimeout(function() {
console.log(111);
console.log(ws);
ws.close();
// createWebSocket();
}, self.timeout);
}, this.timeout)
}
}
實現心跳檢測的思路是:每隔一段固定的時間,向服務器端發送一個ping數據,如果在正常的情況下,服務器會返回一個pong給客戶端,如果客戶端通過
onmessage事件能監聽到的話,說明請求正常,這裏我們使用了一個定時器,每隔3秒的情況下,如果是網絡斷開的情況下,在指定的時間內服務器端並沒有返回心跳響應消息,因此服務器端斷開了,因此這個時候我們使用ws.close關閉連接,在一段時間後(在不同的瀏覽器下,時間是不一樣的,firefox響應更快),
可以通過 onclose事件監聽到。因此在onclose事件內,我們可以調用 reconnect事件進行重連操作。