Skip to content

WebSocket 数据类型

提示

根据 lib.dom.d.ts 可以看到 WebSocket send 方法支持两种类型一种是 string(字符串) 一种是 buffer

ts
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;

(ArrayBufferLike | Blob | ArrayBufferView) 再此统称为 Binary (二进制)

问题:String类型下的JSON类型有何弊端(也叫JSON字符串)

无法直接操作JSON数据

由于字符串类型的 JSON 数据在传输时只是简单的字符序列,因此在接收后需要将其解码为 JSON 格式后才能进行操作。

额外的编码/解码开销

如果服务端要对 JSON 数据进行逻辑判断的话就需要对 JSON 字符串进行编解码,在低延迟密集 io 情况下会有性能问题。

数据校验问题

无法直接校验数据有效性、完整性,需要解码后在进行多层数据校验才能保证数据有效性。

错误处理和异常处理

在字符串类型的 JSON 数据传输中,如果 JSON 格式不正确或包含无效的 JSON 数据,需要在接收后进行解析和校验。这可能会导致错误处理和异常处理的复杂性增加,尤其是在网络传输过程中出现错误的情况下。

问题:String类型下的中文占用字节

取决于当前编码方式,在 UTF-8 编码下,一个中文字符通常占用 3 个字节。而在 UTF-16 或 UTF-32 编码下,一个中文字符可能占用 2 个或 4 个字节。

问题:对比String类型Binary类型下JSON类型该怎么处理比较好

在二进制下像一些业务数据比如用户数据、当前状态等数据。服务器并不太关心的数据(不需要服务器来进行逻辑处理判断)可以采用 JSON String 携带在二进制类型里面。 而需要逻辑处理判断一律采用按 来存取值。

问题:对比String类型Binary类型下中文占用字节

采用TextEncoderorTextDecoder

此特性在 Web Worker 中可用

返回一个新构造的 TextEncoder,它默认使用 UTF-8 编码将码位流转换成字节流。

js
const encoder = new TextEncoder();
const view = encoder.encode("€");
console.log(view); // Uint8Array(3) [226, 130, 172]

let utf8decoder = new TextDecoder(); // default 'utf-8' or 'utf8'
console.log(utf8decoder.decode(view));

采用String.charCodeAtorString.fromCodePointMDN描述

String 的 charCodeAt() 方法返回一个整数,表示给定索引处的 UTF-16 码元,其值介于 0 和 65535 之间。请重点关注 65535 他是 等于 0xffff 正好 两字节

我们可以使用上述两个方法将中文转为 两字节 传输,并且没有任何兼容性。

问题:对比String类型的浮点数怎么减少字节占用

此问题在 webgl 或者游戏需要做数据传输场景里面会经常碰到。

以 three.js 举例:

js
const position = {
  x:13.439221743426785,
  ...
}
console.log(JSON.stringify(position)) // '{"x":13.439221743426785}' 占用 24 字节

采用Float32Array(单精度浮点)orFloat64Array(双精度浮点)

  • Float32Array 可以表示小数点前后一共八位有效数据 (过高会丢精度)
  • Float64Array 可以表示小数点前后一共十六位有效数据 (过高会丢精度)
js
const fl32 = new Float32Array([13.439221743426785]);
console.log(fl32.byteLength); // 4 占用 4 字节

const fl64 = new Float64Array([13.439221743426785]);
console.log(fl64.byteLength); // 8 占用 8 字节

问题:基于Binaty有没有更好的压缩算法

哈夫曼编码 // TODO 待完善

问题:服务端该怎么更高效处理数据

可以定义私有协议,做到按位存取值。

例如: RTU 协议

  • 起始符:RTU 协议以一个特殊的字符作为消息的起始符,这个字符通常是 0x68(ASCII 码中的“h”)。
  • 设备地址:紧跟在起始符后面的一个字节是设备地址,用于标识发送消息的设备地址。
  • 功能码:紧随设备地址后面的一个字节是功能码,用于表示消息的类型和功能。例如,读取线圈状态、读取输入状态、强制执行等。
  • 数据区:功能码后面的字节是数据区,根据具体的功能而定,可能是需要读取的寄存器地址、数量等信息,或者是需要写入的线圈状态、输入状态等信息。
  • 校验码:数据区的后面是校验码,用于确保数据的准确性和完整性。RTU 协议通常使用 CRC(循环冗余校验)算法进行校验。
  • 结束符:RTU 协议以一个特殊的字符作为消息的结束符,这个字符通常是 0x16(ASCII 码中的“&”)。

而在 webSocket 中我们不需要关心 起始符结束符 因此可以简化为

  • 设备地址:用户标识或者交通道唯一 id
  • 功能码:同上。
  • 数据区:同上,也可以直接当做 String JSON。
  • 校验码:同上,这个在基于 http 和应用程序框架下也可以省略。

Site developed by Aomd.