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;// 检测心跳的间隔IDlet 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// CLOSEDif (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 messageswebSocket.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对象来读写缓冲区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 errorswebSocket.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