websocket

什么是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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容