WebSocket 是一种网络通信协议,提供了一个全双工通信渠道,通过一个单一的长期连接允许服务器主动向客户端发送消息。WebSocket 协议的详细规范定义在 RFC 6455 中。
WebSocket 握手
在 WebSocket 连接建立之前,客户端和服务器之间会进行一个 HTTP 握手过程。这个过程开始于客户端发送一个升级的 HTTP 请求,如果服务器同意升级连接,则返回一个 HTTP 响应来确认升级。
客户端请求示例:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Upgrade: websocket
表明客户端想要升级连接到 WebSocket。Connection: Upgrade
表明客户端想要升级当前连接。Sec-WebSocket-Key
是一个 Base64 编码的随机值,用于安全地与服务器进行握手。Origin
表示请求发起的源。
服务器响应示例:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1o/Ujh8z6GglPppW2T5C7ZpWA=
101 Switching Protocols
是 HTTP 状态码,表示协议正在切换。Sec-WebSocket-Accept
是服务器生成的确认密钥,基于客户端的Sec-WebSocket-Key
计算得出。
WebSocket 帧格式
一旦握手完成,客户端和服务器就会开始使用 WebSocket 帧格式进行通信。
WebSocket 帧是通信的基本单位,每个帧都包含了一个或多个部分:
- 帧首部:包含帧的元数据,如终末标志、RSV(保留位)、操作码、掩码标志、payload 长度等。
- 掩码:如果掩码标志设置为真,则跟随一个掩码密钥。
- payload 数据:实际传输的数据。
帧首部字段:
- 终末标志 (
FIN
):1 位,表示帧是否是消息的最后一个帧。 - 保留位 (
RSV1
,RSV2
,RSV3
):每个 1 位,用于将来的扩展。 - 操作码 (
OPCODE
):4 位,定义了帧的类型,如文本、二进制、关闭连接等。 - 掩码标志 (
MASK
):1 位,表示是否使用了掩码。 - payload 长度:7 或 16 位,表示 payload 数据的长度。
掩码:
- 如果
MASK
标志为真,接下来的 4 字节表示掩码密钥。
Payload 数据:
- 帧的实际数据,长度由
payload length
确定。
操作码:
操作码定义了帧的类型,以下是一些常见的操作码:
0x0
:继续帧,用于分片消息。0x1
:文本帧,payload 包含文本数据。0x2
:二进制帧,payload 包含二进制数据。0x8
:关闭连接。0x9
:ping 控制帧。0xA
:pong 控制帧。
示例帧:
假设客户端要发送一个文本消息 "Hello" 到服务器,WebSocket 帧可能如下:
- 首部:
FIN=1
,RSV1=0
,RSV2=0
,RSV3=0
,OPCODE=1
,MASK=1
,payload length=5
- 掩码:
33 22 11 00
(随机生成) - Payload 数据:
48 65 6c 6c 6f
("Hello" 的 UTF-8 编码)
关闭连接:
关闭连接是通过发送一个操作码为 0x8
的控制帧来完成的。关闭帧通常包含一个状态码和一个可选的原因。
WebSocket 协议还包括其他细节,如分帧机制、错误处理、扩展等,但上述内容提供了一个基本的框架,用于理解 WebSocket 的帧格式和通信方式。