一、什么是WebScoket📦
WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
下图是轮询与websocket的区别
1.2、WebSocket 优点
- 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。
- 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少。
- 保持连接状态。与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。
- 更好的二进制支持。WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容。
- 可以支持扩展。WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。
二、WebScoket API👌
在浏览器中要使用 WebSocket 提供的能力,我们就必须先创建 WebSocket 对象,该对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。
2.1、构造函数
const myWebSocket = new WebSocket(url [, protocols]);
- url:表示连接的 URL,这是 WebSocket 服务器将响应的 URL
- protocols(可选):一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个 WebSocket 子协议。比如,你可能希望一台服务器能够根据指定的协议(protocol)处理不同类型的交互。如果不指定协议字符串,则假定为空字符串。
2.2、属性
WebSocket 对象包含以下属性:每个属性的具体含义如下:
- binaryType:使用二进制的数据类型连接。
- bufferedAmount(只读):未发送至服务器的字节数。
- extensions(只读):服务器选择的扩展。
- onclose:用于指定连接关闭后的回调函数。
- onerror:用于指定连接失败后的回调函数。
- onmessage:用于指定当从服务器接受到信息时的回调函数。
- onopen:用于指定连接成功后的回调函数。
- protocol(只读):用于返回服务器端选中的子协议的名字。
- readyState(只读):返回当前 WebSocket 的连接状态,共有 4 种状态:
CONNECTING — 正在连接中,对应的值为 0;
OPEN — 已经连接并且可以通讯,对应的值为 1;
CLOSING — 连接正在关闭,对应的值为 2;
CLOSED — 连接已关闭或者没有连接成功,对应的值为 3。
- url(只读):返回值为当构造函数创建 WebSocket 实例对象时 URL 的绝对路径。
2.3、方法
- close([code[, reason]]):该方法用于关闭 WebSocket 连接,如果连接已经关闭,则此方法不执行任何操作。
- send(data):该方法将需要通过 WebSocket 链接传输至服务器的数据排入队列,并根据所需要传输的数据的大小来增加 bufferedAmount 的值 。若数据无法传输(比如数据需要缓存而缓冲区已满)时,套接字会自行关闭。
2.4、 事件
使用 addEventListener() 或将一个事件监听器赋值给 WebSocket 对象的 oneventname 属性,来监听下面的事件。
- close:当一个 WebSocket 连接被关闭时触发,也可以通过 onclose 属性来设置。
- error:当一个 WebSocket 连接因错误而关闭时触发,也可以通过 onerror 属性来设置。
- message:当通过 WebSocket 收到数据时触发,也可以通过 onmessage 属性来设置。
- open:当一个 WebSocket 连接成功时触发,也可以通过 onopen 属性来设置。
三、其他💂♀️
3.1、WebSocket 与 HTTP 有什么关系
WebSocket 是一种与 HTTP 不同的协议。两者都位于 OSI 模型的应用层,并且都依赖于传输层的 TCP 协议。 虽然它们不同,但是 RFC 6455 中规定:WebSocket 被设计为在 HTTP 80 和 443 端口上工作,并支持 HTTP 代理和中介,从而使其与 HTTP 协议兼容。 为了实现兼容性,WebSocket 握手使用 HTTP Upgrade 头,从 HTTP 协议更改为 WebSocket 协议。
3.2、WebSocket 与长轮询有什么区别
长轮询就是客户端发起一个请求,服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断请求的数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则等待一定的时间后才返回。
长轮询的本质还是基于 HTTP 协议,它仍然是一个一问一答(请求 — 响应)的模式。而 WebSocket 在握手成功后,就是全双工的 TCP 通道,数据可以主动从服务端发送到客户端。
3.3、什么是 WebSocket 心跳
网络中的接收和发送数据都是使用 SOCKET 进行实现。但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机制。所谓 “心跳” 就是定时发送一个自定义的结构体(心跳包或心跳帧),让对方知道自己 “在线”。 以确保链接的有效性。
而所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息,如果服务端几分钟内没有收到客户端信息则视客户端断开。
在 WebSocket 协议中定义了 心跳 Ping 和 心跳 Pong 的控制帧:
- 心跳 Ping 帧包含的操作码是 0x9。如果收到了一个心跳 Ping 帧,那么终端必须发送一个心跳 Pong 帧作为回应,除非已经收到了一个关闭帧。否则终端应该尽快回复 Pong 帧。
- 心跳 Pong 帧包含的操作码是 0xA。作为回应发送的 Pong 帧必须完整携带 Ping 帧中传递过来的 “应用数据” 字段。如果终端收到一个 Ping 帧但是没有发送 Pong 帧来回应之前的 Ping 帧,那么终端可以选择仅为最近处理的 Ping 帧发送 Pong 帧。此外,可以自动发送一个 Pong 帧,这用作单向心跳。