什么是websocket
HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。
优点
1.支持全双工通信,实时性更强,解决长轮询请求的不实时性。
2.更好的二进制支持。
3.较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
4.支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
详细讲解
webSocket心跳
自我理解:websocket连接会因为各种原因断开,我们通过心跳机制去实现一个重连。
连接断开的场景(前端开发者思维)
1.websocket对象监听到连接断开(onclose)或错误发生(onerror):通过监听事件进行重连。
2.websocket对象监听不到连接断开(onclose)或错误发送(onerror):通过心跳机制来进行重连。
详细讲解
webSocket心跳源码
/**
* url: ws链接
* heartCheck: 心跳机制检测对象
* messageCallBack: ws对象onmessage触发的回调,其它事件也可以增加回调,看自己需求
*/
export class SelfWebSocket {
constructor({ url, heartCheck, messageCallBack }) {
this.wsUrl = url
this.ws = null
this.resetClock = false // 重连锁,防止多次重连
this.heartCheck = heartCheck // 心跳对象
this.messageCallBack = messageCallBack
}
// 初始化websocket链接
initWs() {
try {
//检查兼容性
if ('WebSocket' in window) {
this.ws = new WebSocket(this.wsUrl);
} else if ('MozWebSocket' in window) {
this.ws = new MozWebSocket(this.wsUrl);
} else {
alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10以下浏览器,360浏览器请使用极速模式,不要使用兼容模式!");
}
this.initWsEvent(); //初始化websocket事件
this.resetClock = false;
} catch (e) {
console.log('catch', e);
this.reconnect();//重连
}
}
// 初始化websocket事件
initWsEvent() {
this.ws.onopen = () => {
console.log('lzh', '建立连接')
// 开启心跳
this.heartCheck.start(this.ws)
}
this.ws.onmessage = (data) => {
console.log("lzh", "收到数据", data);
// 'health' 是后端和我约定好,我传 'ping',他传'health'
if (data && data.data === 'health') {
this.heartCheck.start(this.ws)
} else if (data && data.data) {
// 调用
this.messageCallBack(data)
}
};
this.ws.onclose = (e) => {
console.log("lzh", "连接关闭");
console.log("lzh", e);
// 移出之前的事件
this.removeWsEvent()
// 重连
this.reconnect()
};
this.ws.onerror = (e) => {
console.log("lzh", "连接出错");
console.log("lzh", e);
// 重连
this.reconnect()
};
}
// 移出websocket监听事件
removeWsEvent() {
this.ws.onopen = null
this.ws.onmessage = null
this.ws.onclose = null
this.ws.onerror = null
}
// websocket重连
reconnect() {
if (this.resetClock) {
return
}
this.resetClock = true
this.initWs()
}
}
/**
* timeout: 心跳发送时间间隔
* serverTimeout:服务器超时认定时间
*/
export class Heartcheck {
constructor({ timeout, serverTimeout }) {
this.timeout = timeout
this.serverTimeout = serverTimeout
this.timeoutObj = null
this.serverTimeoutObj = null
}
start(ws) {
let _this = this
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function () {
ws.send("ping");
_this.serverTimeoutObj = setTimeout(function () {
ws.close(); //服务器超时关闭连接
}, _this.serverTimeout);
}, this.timeout)
}
stop() {
clearTimeout(this.timeout)
clearTimeout(this.serverTimeout)
}
}
参考资料:
http://www.360doc.com/content/22/1110/15/30388632_1055363074.shtml
https://www.codenong.com/cs105391665/
https://www.cnblogs.com/chyingp/p/websocket-deep-in.html