WebSocket 协议介绍

前言

一.通用协议设计

参考链接

bash 复制代码
/*
+---------------------------------------------------------------+
| 魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte  |
+---------------------------------------------------------------+
| 状态 1byte |        保留字段 4byte     |      数据长度 4byte     | 
+---------------------------------------------------------------+
|                   数据内容 (长度不定)          | 校验字段 2byte |
+---------------------------------------------------------------+
*/

待补充

正文

二.WebSocket 协议

2.1 基础数据帧
术语 说明 大小
FIN 如果是 1,表示这是消息(message)的最后一个分片(fragment);如果是 0,表示不是是消息(message)的最后一个分片(fragment) 1bit
RSV1, RSV2, RSV3 一般情况下全为 0。当客户端、服务端协商采用 WebSocket 扩展时,这三个标志位可以非 0,且值的含义由扩展进行定义。如果出现非零的值,且并没有采用 WebSocket 扩展,连接出错 每个1 bit
Opcode 操作代码,Opcode 的值决定了应该如何解析后续的数据载荷(data payload)。如果操作代码是不认识的,那么接收端应该断开连接(fail the connection) 4 bits
Mask 表示是否要对数据载荷进行掩码操作。 从客户端向服务端发送数据时,需要对数据进行掩码操作;从服务端向客户端发送数据时,不需要对数据进行掩码操作。 如果服务端接收到的数据没有进行过掩码操作,服务端需要断开连接。 如果 Mask 是 1,那么在 Masking-key 中会定义一个掩码键(masking key),并用这个掩码键来对数据载荷进行反掩码。所有客户端发送到服务端的数据帧,Mask 都是 1。 1bit
Payload length 数据载荷的长度,单位是字节。假设数 Payload length === x,如果: x 为 0~126:数据的长度为 x 字节。 x 为 126:后续 2 个字节代表一个 16 位的无符号整数,该无符号整数的值为数据的长度。 x 为 127:后续 8 个字节代表一个 64 位的无符号整数(最高位为 0),该无符号整数的值为数据的长度。 此外,如果 payload length 占用了多个字节的话,payload length 的二进制表达采用网络序(big endian,重要的位在前)。 7 bits, 7+16 bits, 或者 7+64 bits
Masking-key 所有从客户端传送到服务端的数据帧,数据载荷都进行了掩码操作,Mask 为 1,且携带了 4 字节的 Masking-key。如果 Mask 为 0,则没有 Masking-key。 备注:载荷数据的长度,不包括 mask key 的长度。 0 or 4 bytes
Payload data "负载数据"定义为"扩展数据"连接"应用数据"。 -Extension data: x byte "扩展数据"是 0 字节除非已经协商了一个扩展。任何扩展必须指定"扩展数据"的长度,或长度是如何计算的,以及扩展如何使用必须在打开阶段握手期间协商。如果存在,"扩展数据"包含在总负载长度中。 - Application data: y bytes 任意的"应用数据",占用"扩展数据"之后帧的剩余部分。"应用数据"的长度等于负载长度减去"扩展数据"长度。 (x+y) bytes

Opcode:

  • %x0 代表一个继续帧
  • %x1 代表一个文本帧
  • %x2 代表一个二进制帧
  • %x3-7 保留用于未来的非控制帧
  • %x8 代表连接关闭
  • %x9 代表 ping
  • %xA 代表 pong
  • %xB-F 保留用于未来的控制帧
2.2 数据帧另外一种表达方式
bash 复制代码
    ws-frame                = frame-fin           ; 1 bit in length
                              frame-rsv1          ; 1 bit in length
                              frame-rsv2          ; 1 bit in length
                              frame-rsv3          ; 1 bit in length
                              frame-opcode        ; 4 bits in length
                              frame-masked        ; 1 bit in length
                              frame-payload-length   ; either 7, 7+16,
                                                     ; or 7+64 bits in
                                                     ; length
                              [ frame-masking-key ]  ; 32 bits in length
                              frame-payload-data     ; n*8 bits in
                                                     ; length, where
                                                     ; n >= 0

    frame-fin               = %x0 ; more frames of this message follow
                            / %x1 ; final frame of this message
                                  ; 1 bit in length

    frame-rsv1              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-rsv2              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-rsv3              = %x0 / %x1
                              ; 1 bit in length, MUST be 0 unless
                              ; negotiated otherwise

    frame-opcode            = frame-opcode-non-control /
                              frame-opcode-control /
                              frame-opcode-cont

    frame-opcode-cont       = %x0 ; frame continuation

    frame-opcode-non-control= %x1 ; text frame
                            / %x2 ; binary frame
                            / %x3-7
                            ; 4 bits in length,
                            ; reserved for further non-control frames

    frame-opcode-control    = %x8 ; connection close
                            / %x9 ; ping
                            / %xA ; pong
                            / %xB-F ; reserved for further control
                                    ; frames
                                    ; 4 bits in length
                                    
    frame-masked            = %x0
                            ; frame is not masked, no frame-masking-key
                            / %x1
                            ; frame is masked, frame-masking-key present
                            ; 1 bit in length

    frame-payload-length    = ( %x00-7D )
                            / ( %x7E frame-payload-length-16 )
                            / ( %x7F frame-payload-length-63 )
                            ; 7, 7+16, or 7+64 bits in length,
                            ; respectively

    frame-payload-length-16 = %x0000-FFFF ; 16 bits in length

    frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF
                            ; 64 bits in length

    frame-masking-key       = 4( %x00-FF )
                              ; present only if frame-masked is 1
                              ; 32 bits in length

    frame-payload-data      = (frame-masked-extension-data
                               frame-masked-application-data)
                            ; when frame-masked is 1
                              / (frame-unmasked-extension-data
                                frame-unmasked-application-data)
                            ; when frame-masked is 0

    frame-masked-extension-data     = *( %x00-FF )
                            ; reserved for future extensibility
                            ; n*8 bits in length, where n >= 0

    frame-masked-application-data   = *( %x00-FF )
                            ; n*8 bits in length, where n >= 0

    frame-unmasked-extension-data   = *( %x00-FF )
                            ; reserved for future extensibility
                            ; n*8 bits in length, where n >= 0

    frame-unmasked-application-data = *( %x00-FF )
                            ; n*8 bits in length, where n >= 0
2.3 WebSocket掩码的作用

WebSocket的掩码算法是一种数据加密方法,‌用于保护数据传输的安全性。‌这种算法通过异或运算对数据进行处理,‌以防止早期版本的协议中存在的代理缓存污染攻击等问题。‌具体来说,‌掩码算法的实现过程如下:‌

  1. 掩码的作用:‌掩码算法并不是为了防止数据泄密,‌而是为了防止代理缓存污染攻击等问题。‌它通过对数据进行异或运算,‌使得原始数据在传输过程中被改变,‌只有在接收端使用相同的掩码进行反向操作,‌才能还原出原始数据。‌

  2. 算法描述:‌对于每个需要发送的字节,‌它通过与掩码密钥进行异或运算来生成传输的数据。‌具体来说,‌对于原始数据中的每个字节original-octet-i,‌它首先计算j = i MOD 4来获取掩码密钥中的对应字节masking-key-octet-j,为mask key第j个字节。‌然后,‌将original-octet-i与masking-key-octet-j进行异或运算,‌得到的结果即为传输的数据

    即:j = i MOD 4

    transformed-octet-i = original-octet-i XOR masking-key-octet-j。‌

bash 复制代码
void umask(char *payload, int len, char *mask)
{
    int i = 0;
    for (i = 0; i < len; i++)
    {
        payload[i] ^= mask[i % 4];
    }
}
  1. 示例:‌以客户端发送语音文件到服务端的场景为例,‌客户端首先发送txt消息文件名称,‌然后再发送bin消息二进制流数据。‌在这个过程中,‌客户端对需要发送的字符与掩码进行异或运算,‌生成用于网络传输的数据。‌例如,‌字符't'的ASCII值为116,‌与掩码14进行异或运算后,‌得到的结果用于传输。‌

待补充

2.4 分片(Fragmentation)
2.5 控制帧
2.5.1 Close
2.5.2 Ping
2.5.3 Pong
2.6 数据帧(payload)

三、私有协议示例

相关推荐
李白你好8 分钟前
家用无线路由器的 2.4GHz 和 5GHz
运维·网络
嵌入(师)22 分钟前
嵌入式驱动开发详解21(网络驱动开发)
网络·驱动开发
柒烨带你飞1 小时前
路由器的原理
网络·智能路由器·php
xserver21 小时前
ensp 基于EASY IP的公司出口链路配置
网络·tcp/ip·智能路由器
枫零NET1 小时前
学习思考:一日三问(学习篇)之匹配VLAN
网络·学习·交换机
手心里的白日梦2 小时前
UDP传输层通信协议详解
网络·网络协议·udp
等一场春雨2 小时前
springboot 3 websocket react 系统提示,选手实时数据更新监控
spring boot·websocket·react.js
却道天凉_好个秋2 小时前
音视频学习(二十八):websocket-flv
websocket·音视频·flv
红米饭配南瓜汤2 小时前
WebRTC服务质量(11)- Pacer机制(03) IntervalBudget
网络·网络协议·音视频·webrtc·媒体