认识全双工通讯 webSocket

151 阅读3分钟

websocket是什么

HTML5开始提供的一种浏览器与服务器之间进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需完成一次握手,两者之间就可以直接建立持久性的连接,并且进行双向数据传输,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯(例如:微信聊天就属于双向数据传输)。

在 webSocket 之前很多网站使用推送技术,所用的都是ajax轮询。轮询是在规定的时间间隔中通过http向服务器发送请求,然后接收服务器的响应。这种方式需要浏览器不断的向服务器发送请求,就显得繁琐,并且http请求可能包含较长头数据,显然这样会浪费很多的带宽等资源。

websocket 相对于http的优点

1、支持双向通信,实时性更强。
2、更好的二进制支持(websocket是以二进制数据推送过来的)。
3、较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)

websocket建立连接

//建立连接以后,客户端和服务器端就可以通过 TCP 连接直接交换数据,可用 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据
/*
url:建立 websocket url
protocol: 子协议
*/
var Socket = new WebSocket(url, [protocol] );

Websocket属性

// Socket.readyState(表示连接状态)	
0 - 表示连接尚未建立。
1 - 表示连接已建立,可以进行通信。
2 - 表示连接正在进行关闭。
3 - 表示连接已经关闭或者连接不能打开。

websocket事件

事件	     事件处理程序	   描述
open	     Socket.onopen	   连接建立时触发
message	     Socket.onmessage	   客户端接收服务端数据时触发
error	     Socket.onerror	   通信发生错误时触发
close	     Socket.onclose	   连接关闭时触发

websocket方法

//使用连接向服务器发送数据
Socket.send()	
// 关闭websocket连接
Socket.close()	

websocket.png

封装websocket函数


class WebsocketJs{
    constructor({socket,
                 socket_url,   //ws 路径
                 socket_open=false, //开启标志
                 hearbeat_timer, //心跳定时器
                 hearbeat_interval= 5000, // 发送心跳频率

                 is_reonnect = true, //是否自动重连
                 reonnect_count = 3, //重连次数
                 reonnect_current = 1, //已经重连次数
                 reonnect_timer, //重连定时器
                 reonnect_interval = 5000,//重连频率
                }){
        this.socket = null;
        this.socket_url = socket_url;
        this.initSocket()
        this.onmessage = null;
        this.socket_open = socket_open;
        this.hearbeat_timer = hearbeat_timer; //null
        this.hearbeat_interval = hearbeat_interval;

        this.is_reonnect = is_reonnect;
        this.reonnect_timer = reonnect_timer;//null
        this.reonnect_interval = reonnect_interval;
        this.reonnect_current = reonnect_current;
        this.reonnect_count = reonnect_count;

    }
    // 初始化
    initSocket(){
        if( !("WebSocket" in window) ){
            console.log('浏览器不支持WebSocket')
            return null
        }
        this.socket = new WebSocket(this.socket_url)

        // 接收到服务器返回的数据 可以通过外部传入进行回调
        this.socket.onmessage = function(e){
            console.log(e)
            this.receive(e)
        }
        // 连接上服务器
        this.socket.onopen = function(e){
            console.log(e) //可以做一些重连接操作
            console.log('连接上服务器')
            this.socket_open = true; //开启websocket
            this.is_reonnect = true; //开启重连
            this.hearBeat(); //开启心跳
        }
        //关闭连接
        this.socket.onclose = function (e) {
            // clearInterval(this.hearbeat_interval)
            this.socket_open = false;
            //是否需要重连
            if (this.is_reonnect){
                this.reonnect_timer = setInterval(()=>{
                    // 当前重连数 > 总连接数 就放弃请求
                    if (this.reonnect_current > this.reonnect_count){
                        clearTimeout(this.reonnect_timer)
                        return
                    }
                    // 记录重连次数
                    this.reonnect_current++
                    this.reconnect();
                },this.reonnect_interval)
            }
        }
        //连接报错
        this.socket.onerror = function (e) {
            console.log(e);
        }
    }
    
    // 心跳(是否还活着)
    hearBeat(){
        // 判断之前是否有过开启过心跳
        if (this.hearbeat_timer){
            clearInterval(this.hearbeat_timer)
        }
        this.hearbeat_timer = setInterval(()=>{
            this.socket.send(data) //需要向服务器发送的数据
        },this.hearbeat_interval)
    }
    // 接收消息
    receive(message){
        // 获取到数据 -- 看自己业务进行修改
        var params = JSON.parse(message.data)
    }


    // 发送消息
    send(data,callback=null){
        //callback()
        // this.socket.OPEN 是打开时返回的状态
        if (this.socket.readyState === this.socket.OPEN){
            this.socket.send(JSON.stringify(data))
        }else if(this.socket.readyState === this.socket.CONNECTING){// 正在开启状态,则等待1s后重新调用
            setTimeout(function () {
                this.send(data)//,callback
            }, 1000)
        }else { // 未开启,则等待1s后重新调用
            this.initSocket()
            setTimeout(function () {
                this.send(data) //, callback
            }, 1000)
        }
        // if (callback) {
        //     callback()
        // }
    }
    // 重新连接
    reconnect(){
        // 重新发起连接(如果有开启则关闭)
        if (this.socket && this.socket_open) {
            this.close()
        }
        this.initSocket();
    }
    // 主动关闭请求
    close(){
        console.log('主动关闭')
        clearInterval(this.hearbeat_timer)
        this.is_reonnect = false
        // this.socket.close()
    }
}