WebSocket 数据类型
提示
根据 lib.dom.d.ts
可以看到 WebSocket send 方法支持两种类型一种是 string
(字符串) 一种是 buffer
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 编码将码位流转换成字节流。
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.charCodeAt
orString.fromCodePoint
MDN描述
String 的 charCodeAt() 方法返回一个整数,表示给定索引处的 UTF-16 码元,其值介于 0 和 65535 之间。请重点关注 65535
他是 等于 0xffff
正好 两字节
我们可以使用上述两个方法将中文转为 两字节 传输,并且没有任何兼容性。
问题:对比String类型的浮点数怎么减少字节占用
此问题在 webgl 或者游戏需要做数据传输场景里面会经常碰到。
以 three.js 举例:
const position = {
x:13.439221743426785,
...
}
console.log(JSON.stringify(position)) // '{"x":13.439221743426785}' 占用 24 字节
采用Float32Array(单精度浮点)orFloat64Array(双精度浮点)
- Float32Array 可以表示小数点前后一共八位有效数据 (过高会丢精度)
- Float64Array 可以表示小数点前后一共十六位有效数据 (过高会丢精度)
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 和应用程序框架下也可以省略。