WebSocket基本介绍
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
WebSocket 状态
在上面代码中我们通过WebSocket()构造函数来构造一个ws实例。对应的这个实例中有只读属性 readyState 表示连接状态四个状态,对应的分别有四个不同的值,具体如下:
| 状态 | 值 | 说明 | 
|---|---|---|
| WebSocket.CONNECTING | 0 | 表示连接尚未建立 | 
| WebSocket.OPEN | 1 | 表示连接已建立,可以进行通信 | 
| WebSocket.CLOSING | 2 | 表示连接正在进行关闭 | 
| WebSocket.CLOSED | 3 | 表示连接已经关闭或者连接不能打开 | 
WebSocket 事件
整个ws建立的过程有四个比较重要的事件,分别是:
- open阶段:WebSocket.onopen属性定义一个事件处理程序,当WebSocket 的连接状态readyState 变为1时调用;这意味着当前连接已经准备好发送和接受数据。这个事件处理程序通过 事件(建立连接时)触发
 - message:message 事件会在 WebSocket 接收到新消息时被触发
 - close:WebSocket.onclose 属性返回一个事件监听器,这个事件监听器将在 WebSocket 连接的readyState 变为 CLOSED时被调用,它接收一个名字为“close”的 CloseEvent 事件
 - error:当websocket的连接由于一些错误事件的发生 (例如无法发送一些数据) 而被关闭时,一个error事件将被引发
 
WebSocket 方法
在ws中我们常用的有如下两个方法:
- send:使用连接发送数据
 - close:关闭连接
 
HTML中建立ws
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>websocket-demo</title>
</head>
<body>
</body>
<script>
  // 建立ws连接
  const wbSocket = () => {
    // ws实例
    let webSocket = null;
    // 检测心跳的间隔ID
    let intervalID = null;
    const connect = async () => {
      // 服务端ws的地址
      const wsUrl = 'ws://10.199.161.17:9010/ws?deviceId=A51a007F-0620-467B-8A4a-c8a6c9aD69FD&protocolVersion=3'
      // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
      // CLOSED
      if (webSocket && webSocket.readyState !== 3) {
        return;
      }
      // Create WebSocket connection.
      webSocket = new WebSocket(wsUrl);
      // 连接已经准备好发送和接受数据
      webSocket.addEventListener("open", (event) => {
        webSocket.send("Hello Server, connection has build", event);
      });
      // Listen for messages
      webSocket.addEventListener("message", async (event) => {
        console.log("Message from server: ", event.data);
        const receivedData = event.data;
        if (receivedData instanceof Blob) {
          try {
            const buffer = await event.data.arrayBuffer()
            // 建立DateView对象来读写缓冲区 按照有符号的8位数字读取
            const view = new Int8Array(buffer);
            // 将类数组view转化为数组,方便读取
            const list = Array.from(view)
            console.log(list);
          } catch (error) {
            console.log('解析blob出错', error.message);
          }
        } else {
          console.log('接受到的数据');
        }
      });
      // Listen for possible errors
      webSocket.addEventListener("error", (event) => {
        console.log("WebSocket error: ", event);
      });
      webSocket.addEventListener("close", event => {
        console.log("socket closed ", event.data);
        // 将webSocket 设为Null, 不再发送心跳 等待重新建立连接
        clearInterval(intervalID)
        webSocket = null;
        intervalID = null;
      });
    }
    
    setInterval(() => {
      // 如果有socket实例并且有心跳就直接返回
      if (webSocket && webSocket) return
      // 无ws实力 or 心跳id则建立ws连接
      connect()
    }, 5 * 1000)
  }
  wbSocket()
</script>
</html>
 
可以看到在上面代码中我们对服务端返回给前端的值做了一层判定,有时服务端在特定的场景下会使用java中的netty这个工具包返回给前端的数据是二进制的,就需要前端判断之后自己再使用arrayBuffer这个API自己转一下。
 如果服务端此时返回的是一个正常的数据而非Blob的话,那就可以直接在event.data中获取就可以了。
 需要注意一点是ArrayBuffer是一个表示原始二进制数据的缓冲区,是一个字节数组,并不能直接操作ArrayBuffer中的内容。需要通过DataView对象来操作
浏览器中查看ws

 如果打印出上面代码中的buffer的话console.log(111, buffer);会在浏览器如下显示:
 
 我们点击右侧的那个点之后,会跳转到浏览器的内存检查器,查看对应的值以及存这些值的地址。
 
参考资料
WebSocket
 HTML5 WebSocket
 ArrayBuffer


















