WebSocket

2022-05-20  本文已影响0人  心存美好

WebSocket

1. WebSocket 理解

1.1 WebSocket出现的原因

我们已经有了 HTTP 协议,为什么还需要另一个协议?

因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。因此我们只能使用"轮询", 也就是每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

<body>
  <script>
    //http是单向的,要东西才会给
     setInterval(() => {
      $.ajax({   //每隔10s向后台请求数据,这就是轮询
        ...
      })
    }, 10000)
  </script>
</body>

然而轮询的效率比较低, 非常 浪费资源。轮询的缺陷--后台数据没变,间隔响应时间还会请求数据

因此为了更好地处理这种问题.WebSocket就 这样被发明了

1.2 WebSocket 简介

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

特点 :
  1. 建立在 TCP 协议之上,服务器端的实现比较容易。

  2. 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器

  3. 数据格式比较轻量,性能开销小,通信高效。

  4. 可以发送文本,也可以发送二进制数据。

  5. 没有同源(跨域)限制,客户端可以与任意服务器通信。

  6. 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

ws://example.com:80/some/path

2. 客户端API

2.1 WebSocket 构造函数

WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。

对于我们来时通过WebSocket构造函数实例化WebSocket对象, 在实例化过程中连接服务器

语法;
var aWebSocket = new WebSocket(url);
参数:
  1. url: 要连接的URL;这应该是WebSocket服务器将响应的URL

例子:

let ws = new WebSocket('ws://www.localhost:8080')在关闭
4. CLOSED: 值为3, 表示连
2.2 webSocket.readyState

实例的readyState 属性返回实例对象的当前状态, 共有四种状态

  1. CONNECTING: 值为0, 表示正在连接
  2. OPEN: 值为1, 表示连接成功, 可以通信了
  3. CLOSING: 值为2, 表示连接正接已经关闭, 或者 打开连接失败
switch (ws.readyState) {
  case WebSocket.CONNECTING:
    break;
  case WebSocket.OPEN:
    break;
  case WebSocket.CLOSING:
    break;
  case WebSocket.CLOSED:
    break;
  default:
    break;
}
3 webSocket.onopen

实例对象的onopen 方法, 用于执行连接成功后的回调函数

// socket 连接成功后触发事件
ws.onopen = function(){
   // 像后端发送数据 
    ws.send("Hello Word")
}

如果需要指定多个回调函数, 可以使用addEventListener事件绑定

ws.addEventListener('open', function (ev) {
   ws.send('Hello Server!');
});
ws.addEventListener('open', function (ev) {
   ws.send('你好');
});
2.4 webSocket.send()

实例对象的send()方法用于向服务器发送数据。

发送文本数据

ws.send('hello word');

发送JSON数据

ws.send(JSON.stringify({name:'张三'}));
2.5 webSocket.onmessage

实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。

ws.onmessage = function(ev) {
  var data = ev.data;
  // 处理数据
};

ws.addEventListener("message", function(ev) {
  var data = ev.data;
  // 处理数据
});
2.6 webSocket.onclose

实例对象的onclose 属性, 指定连接关闭后的回调函数

注意: socket连接失败也会触发onclose事件

ws.onclose = function(ev) {
  console.log('关闭socket连接', ev)
};

ws.addEventListener("close", function(event) {
  console.log('关闭socket连接', ev)
});
2.7 webSocket.onerror

实例对象的onerror属性,用于指定报错时的回调函数。

socket.onerror = function(ev) {
  // 处理错误
};

socket.addEventListener("error", function(ev) {
  // 处理错误
});

3. WebSocket 封装

class JsSocket {

    /**
       *  构造方法, 进行初始化
       *  @param {String} url socket 连接地址
       * */
    constructor(url) {
        this.url = url;
        this.lockReconnect = false;
        this.reconnectCount = 0
    }

    /**
       * 开始连接
       * @params { Function } callback  
       * */
    connect(callback) {
        this.callback = callback;
        this.disconnect()

        try {
            console.log("JsSocket开始连接...", this.url)
            this.ws = new WebSocket(this.url)

            this.ws.onopen = function(ev) {
                console.log("JsSocket onpen...", ev)
                this.reconnectTimes = 0
            }

            this.ws.onmessage = function(ev) {
                console.log("JsSocket onmessage...", ev)
                let data = ev.data;
                if (!data) {
                    data = JSON.parse(data)
                }


                callback(data)
            }

            this.ws.onclose = (ev) => {
                console.log("JsSocket onclose...", ev)
                this.reconnect()
            }

            this.ws.onerror = (ev) => {
                console.log("JsSocket onerror...", ev)
                this.reconnect()
            }
        } catch (error) {
            console.log("JsSocket", error)
        }
    }


    /**
       * 断开连接
       * */
    disconnect() {
        if (this.ws) {
            this.ws.onclose = null;
            this.ws.close()
            this.ws = null
        }
    }


    /**
       * 发送消息
       * @params { Object } data 消息内容
       * */
    send(data) {
        if (this.ws) {
            this.ws.send(data)
        }
    }


    /**
       * 重新连接
       * */
    reconnect() {
        if (this.lockReconnect || this.reconnectCount > 5) {
            console.log('JsSocket 重连锁定 或者 超过重连次数')
            return;
        }
        this.lockReconnect = true;
        setTimeout(() => {
            this.reconnectCount++;
            console.log('JsSocket 重连...')
            this.connect(this.callback)
            this.lockReconnect = false
        }, 3000)
    }
}
上一篇 下一篇

猜你喜欢

热点阅读