天天看点

client心跳 websocket_javascript websocket 心跳检测机制介绍

====测试代码:

==index.html

Document abc

==websocket.js

var lockReconnect = false; //避免ws重复连接

var ws = null; //判断当前浏览器是否支持WebSocket

var wsUrl = null;var config ={};functionsocketLink(set) {

config=set;

wsUrl=config.url;

createWebSocket(wsUrl);//连接ws

}functioncreateWebSocket(url) {try{if ('WebSocket' inwindow) {

ws= new WebSocket(url, 'echo-protocol');

}else if ('MozWebSocket' inwindow) {

ws= new MozWebSocket(url, 'echo-protocol');

}else{

alert("您的浏览器不支持websocket")

}

initEventHandle();

}catch(e) {

reconnect(url);

console.log(e);

}

}functioninitEventHandle() {

ws.onclose= function() {

reconnect(wsUrl);

console.log("llws连接关闭!" + newDate().toUTCString());

};

ws.οnerrοr= function() {

reconnect(wsUrl);

console.log("llws连接错误!");

};

ws.onopen= function() {

heartCheck.reset().start();//心跳检测重置

console.log("llws连接成功!" + newDate().toUTCString());

config.open(ws)

};

ws.onmessage= function(event) { //如果获取到消息,心跳检测重置

heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的

config.msg(event.data,ws)

};

}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。

window.onbeforeunload = function() {

ws.close();

}functionreconnect(url) {if (lockReconnect) return;

lockReconnect= true;

setTimeout(function() { //没连接上会一直重连,设置延迟避免请求过多

createWebSocket(url);

lockReconnect= false;

},2000);

}//心跳检测

var heartCheck ={

timeout:10000, //9分钟发一次心跳

timeoutObj: null,

serverTimeoutObj:null,

reset:function() {

clearTimeout(this.timeoutObj);

clearTimeout(this.serverTimeoutObj);return this;

},

start:function() {var self = this;this.timeoutObj = setTimeout(function() {//这里发送一个心跳,后端收到后,返回一个心跳消息,

//onmessage拿到返回的心跳就说明连接正常

ws.send("ping");

console.log("ping!")

self.serverTimeoutObj= setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了

console.log("try=close")

ws.close();//这里为什么要在send检测消息后,倒计时执行这个代码呢,因为这个代码的目的时为了触发onclose方法,这样才能实现onclose里面的重连方法

//所以这个代码也很重要,没有这个方法,有些时候发了定时检测消息给后端,后端超时(我们自己设定的时间)后,不会自动触发onclose方法。我们只有执行ws.close()代码,让ws触发onclose方法

//的执行。如果没有这个代码,连接没有断线的情况下而后端没有正常检测响应,那么浏览器时不会自动超时关闭的(比如谷歌浏览器),谷歌浏览器会自动触发onclose

//是在断网的情况下,在没有断线的情况下,也就是后端响应不正常的情况下,浏览器不会自动触发onclose,所以需要我们自己设定超时自动触发onclose,这也是这个代码的

//的作用。}, self.timeout)

},this.timeout)

}

}

心跳检测的目的时什么呢?

一个是为了定时发送消息,使连接不超时自动断线,可能后端设了超时时间就会自动断线,所以需要定时发送消息给后端,让后端服务器知道连接还在通消息不能断。

二来是为了检测在正常还连接着的情况下,判断后端是否正常,如果我们发了一个定时检测给后端,后端按照约定要下发一个检测消息给前端,这样才是正常的。

可是如果后端没有正常下发呢,我们就要设定一下超时要重连了,我们把重连写在了onclose里面,当时正常连接的情况下,超时未能响应检测消息的情况下,浏览器不会自动断掉触发onclose,所以需要我们手动触发,也就是在超时里写一个ws.close()让ws关闭触发onclose方法,实现重连。

==浏览器会触发onclose的情况是断网断线的情况下,当时正常连接还未断线,浏览器时不会自动触发onclose的,所以就有超时手动触发onclose的必要。

self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了

console.log("try=close")

ws.close();//这里为什么要在send检测消息后,倒计时执行这个代码呢,因为这个代码的目的时为了触发onclose方法,这样才能实现onclose里面的重连方法

//所以这个代码也很重要,没有这个方法,有些时候发了定时检测消息给后端,后端超时(我们自己设定的时间)后,不会自动触发onclose方法。我们只有执行ws.close()代码,让ws触发onclose方法

//的执行。如果没有这个代码,连接没有断线的情况下而后端没有正常检测响应,那么浏览器时不会自动超时关闭的(比如谷歌浏览器),谷歌浏览器会自动触发onclose

//是在断网的情况下,在没有断线的情况下,也就是后端响应不正常的情况下,浏览器不会自动触发onclose,所以需要我们自己设定超时自动触发onclose,这也是这个代码的

//的作用。

}, self.timeout)

ws.onopen = function() {

heartCheck.reset().start();//心跳检测重置 在open的时候触发心跳检测

console.log("llws连接成功!" + newDate().toUTCString());

config.open(ws)

};

ws.onmessage= function(event) { //如果获取到消息,心跳检测重置

heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的 //如果后端有下发消息,那么就会重置初始化心跳检测,除非超时没下发,那么就会触发onclose

//然后触发重连

config.msg(event.data,ws)

};

==client.js

var number=0;var config ={

url:'ws://localhost:8080/',

open: (ws)=>{functionsendNumber() {if (ws.readyState ===ws.OPEN) {

number= number+1;

ws.send(number.toString());

setTimeout(sendNumber,1000);

}

}

sendNumber()

},

msg: (data)=>{

console.log(data,"msg")

}

}

socketLink(config)

==node 后端测试代码:

#!/usr/bin/env node

var WebSocketServer = require('websocket').server;var http = require('http');var server = http.createServer(function(request, response) {

console.log((new Date()) + ' Received request for ' +request.url);

response.writeHead(404);

response.end();

});

server.listen(8080, function() {

console.log((new Date()) + ' Server is listening on port 8080');

});

wsServer= newWebSocketServer({

httpServer: server,//You should not use autoAcceptConnections for production

//applications, as it defeats all standard cross-origin protection

//facilities built into the protocol and the browser. You should

//*always* verify the connection's origin and decide whether or not

//to accept it.

autoAcceptConnections: false});functionoriginIsAllowed(origin) {

console.log(origin,"origin")//put logic here to detect whether the specified origin is allowed.

return true;

}

wsServer.on('request', function(request) {if (!originIsAllowed(request.origin)) {//Make sure we only accept requests from an allowed origin

request.reject();

console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');return;

}var connection = request.accept('echo-protocol', request.origin);

console.log((new Date()) + ' Connection accepted.');

connection.on('message', function(message) {if (message.type === 'utf8') {

console.log('Received Message: ' +message.utf8Data);//connection.sendUTF(message.utf8Data); //注释掉是为了测试前端在没后端响应却连接着的情况下,是什么反应。

} else if (message.type === 'binary') {

console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');

connection.sendBytes(message.binaryData);

}

});

connection.on('close', function(reasonCode, description) {

console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');

});

});