websocket简介
websocket简介

websocket简介

1.WebScoket简介

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。

2.与HTTP有什么区别

HTTP协议只能实现客户端请求,服务端响应的这种单项通信。

而WebSocket可以实现客户端与服务端的双向通讯。

最大的区别就是可以做到服务端主动将消息推送给客户端。

总而言之:HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

那么为什么要设计WebScoket呢?

也正是HTTP 协议无法实现服务器主动向客户端发起消息,尽管采用轮训调用的方式,效率低、资源消耗大。 WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。

WebScoket的优势特点

image-20230912101247736

  • 握手阶段采用 HTTP 协议。
  • 数据格式轻量,性能开销小。客户端与服务端进行数据交换时,服务端到客户端的数据包头只有2到10字节,客户端到服务端需要加上另外4字节的掩码。HTTP每次都需要携带完整头部。
  • 更好的二进制支持,可以发送文本,和二进制数据
  • 没有同源限制,客户端可以与任意服务器通信
  • 协议标识符是ws或wss,请求的地址就是后端支持WebSocket的API。
  • 没有同源限制,客户端可以与任意服务器通信
  • 协议标识符是ws或wss,请求的地址就是后端支持WebSocket的API。

3.websocket底层实现原理

建立握手-客户端

image-20230912102229076

  • Origin:所有浏览器将会发送一个 Origin请求头。 你可以将这个请求头用于安全方面(检查是否是同一个域,白名单/ 黑名单等),如果你不喜欢这个请求发起源,你可以发送一个403 Forbidden。需要注意的是非浏览器只能发送一个模拟的 Origin。大多数应用会拒绝不含这个请求头的请求。
  • Sec-WebSocket-Key:是一个 Base64 encode 的值,这个是浏览器随机生成的,告诉服务器:验证是不是真的是Websocket助理
  • Sec_WebSocket-Protocol:是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
  • Sec-WebSocket-Version: 是告诉服务器所使用的 Websocket Draft(协议版本)

建立握手-服务端

image-20230912102246657

  • Sec-WebSocket-Key:它通过客户端发送的Sec-WebSocket-Key 计算出来。计算方法:
    • 将 Sec-WebSocket-Key 跟 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接;
    • 通过 SHA1 计算出摘要,并转成 base64 字符串。
      Sec-WebSocket-Key / Sec-WebSocket-Accept 的主要作用还是为了避免一些网络通信过程中,一些非期待的数据包,”乱入“进来,导致一些错误的响应,并不能用于实现登录认证和数据安全,这些功能还需要应用层自己实现。

传输协议

Websocket的数据传递采用frame形式,会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:

  1. 大数据的传输可以分片传输,可以避免数据大小导致的长度标志位不足够的情况。
  2. 和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。

frame 是客户端和服务端数据传输的最小单元, 当一条消息过长时, 通信方可以将该消息拆分成多个 frame 发送, 接收方收到以后重新拼接、解码从而还原出完整的消息, 在 WebSocket 中, frame 有多种类型, frame 的类型由 frame 头部的 Opcode 字段指示, WebSocket frame 的结构如下所示:

image-20230912102634288

该结构的字段语义如下:

  • FIN, 长度为 1 比特, 该标志位用于指示当前的 frame 是消息的最后一个分段, 因为 WebSocket 支持将长消息切分为若干个 frame 发送, 切分以后, 除了最后一个 frame, 前面的 frame 的 FIN 字段都为 0, 最后一个 frame 的 FIN 字段为 1, 当然, 若消息没有分段, 那么一个 frame 便包含了完成的消息, 此时其 FIN 字段值为 1。
  • RSV 1 ~ 3, 这三个字段为保留字段, 只有在 WebSocket 扩展时用, 若不启用扩展, 则该三个字段应置为 1, 若接收方收到 RSV 1 ~ 3 不全为 0 的 frame, 并且双方没有协商使用 WebSocket 协议扩展, 则接收方应立即终止 WebSocket 连接。
  • Opcode, 长度为 4 比特, 该字段将指示 frame 的类型, RFC 6455 定义的 Opcode 共有如下几种:
    • 0x0, 代表当前是一个 continuation frame,既被切分的长消息的每个分片frame
    • 0x1, 代表当前是一个 text frame
    • 0x2, 代表当前是一个 binary frame
    • 0x3 ~ 7, 目前保留, 以后将用作更多的非控制类 frame
    • 0x8, 代表当前是一个 connection close, 用于关闭 WebSocket 连接
    • 0x9, 代表当前是一个 ping frame
    • 0xA, 代表当前是一个 pong frame
    • 0xB ~ F, 目前保留, 以后将用作更多的控制类 frame
  • Mask, 长度为 1 比特, 该字段是一个标志位, 用于指示 frame 的数据 (Payload) 是否使用掩码掩盖, RFC 6455 规定当且仅当由客户端向服务端发送的 frame, 需要使用掩码覆盖, 掩码覆盖主要为了解决代理缓存污染攻击 (更多细节见 RFC 6455 Section 10.3)。
  • Payload Len, 以字节为单位指示 frame Payload 的长度, 该字段的长度可变, 可能为 7 比特, 也可能为 7 + 16 比特, 也可能为 7 + 64 比特. 具体来说, 当 Payload 的实际长度在 [0, 125] 时, 则 Payload Len 字段的长度为 7 比特, 它的值直接代表了 Payload 的实际长度; 当 Payload 的实际长度为 126 时, 则 Payload Len 后跟随的 16 位将被解释为 16-bit 的无符号整数, 该整数的值指示 Payload 的实际长度; 当 Payload 的实际长度为 127 时, 其后的 64 比特将被解释为 64-bit 的无符号整数, 该整数的值指示 Payload 的实际长度。
  • Masking-key, 该字段为可选字段, 当 Mask 标志位为 1 时, 代表这是一个掩码覆盖的 frame, 此时 Masking-key 字段存在, 其长度为 32 位, RFC 6455 规定所有由客户端发往服务端的 frame 都必须使用掩码覆盖, 即对于所有由客户端发往服务端的 frame, 该字段都必须存在, 该字段的值是由客户端使用熵值足够大的随机数发生器生成, 关于掩码覆盖, 将下面讨论, 若 Mask 标识位 0, 则 frame 中将设置该字段 (注意是不设置该字段, 而不仅仅是不给该字段赋值)。
  • Payload, 该字段的长度是任意的, 该字段即为 frame 的数据部分, 若通信双方协商使用了 WebSocket 扩展, 则该扩展数据 (Extension data) 也将存放在此处, 扩展数据 + 应用数据, 它们的长度和便为 Payload Len 字段指示的值。

4.Websocket属性

属性
Socket.readyState 只读属性 readyState 表示连接状态,可以是以下值: · 表示连接尚未建立。1表示连接已建立,可以进行通信。2表示连接正在进行关闭。3表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数

5.Websocket事件

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

6.WebScoket的方法

方法 描述
Socket.send() 使用连接发送数据
Socket.close() 关闭连接

7.WebScoket的使用方法

发表回复

您的电子邮箱地址不会被公开。