WebSocket 总结
一、是什么?
WebSocket 是一种全双工、持久连接 的网络通信协议,位于 OSI 第七层(应用层),在 TCP 之上运行。它允许客户端和服务器在单个 TCP 连接上同时双向发送消息,无需像 HTTP 那样每次请求都要重新建立连接。
二、核心特点
| 特点 | 说明 |
|---|---|
| 全双工 | 双方可随时主动发送消息,没有"请求-响应"的强制顺序 |
| 持久连接 | 握手成功后,连接保持开放,直到任意一方主动关闭 |
| 低延迟 | 省去了 HTTP 重复的握手头开销,消息边界清晰,无粘包问题 |
| 协议内建控制帧 | 支持 Ping/Pong(心跳)、关闭帧等,无需应用层额外设计 |
| 基于 TCP | 可靠传输,自带序列号和重传机制 |
| 跨端口复用 | 与 HTTP 共享 80/443 端口,便于穿透防火墙 |
三、与 HTTP 的关系
- 非替代,而是升级 :WebSocket 握手使用 HTTP 的
Upgrade机制,握手成功后协议切换。 - 相同之处 :
- URL 模式:
ws://(类似http://)、wss://(类似https://,使用 TLS 加密)。 - 握手阶段可携带自定义 Header(如
Authorization、Cookie)。
- URL 模式:
- 不同之处 :
- HTTP 是半双工(请求→响应结束),WebSocket 是全双工。
- HTTP 每个请求都有头部开销,WebSocket 头部只有 2~14 字节。
- WebSocket 不粘包(基于帧),HTTP 基于文本的行/空行边界。
四、握手过程(简化)
-
客户端发送 HTTP 请求(升级到 WebSocket):
GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 -
服务器响应 101 Switching Protocols:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -
握手完成,TCP 连接保持,进入数据帧传输阶段。
五、数据帧格式(核心)
| 字段 | 长度 | 说明 |
|---|---|---|
| FIN | 1 bit | 是否为消息最后一帧(0=分片,1=完整) |
| RSV1-3 | 3 bits | 扩展保留,通常为 0 |
| Opcode | 4 bits | 帧类型:1=文本,2=二进制,8=关闭,9=Ping,10=Pong,0=续帧 |
| MASK | 1 bit | 是否掩码(客户端→服务器必须为 1) |
| Payload len | 7 bits | 载荷长度提示:0-125 直接表示,126 后跟 2 字节,127 后跟 8 字节 |
| Extended Payload Len | 0, 2, 8 字节 | 当 Payload len 为 126 或 127 时提供实际长度 |
| Masking Key | 0 或 4 字节 | 若 MASK=1,则存在,用于解码载荷 |
| Payload Data | 变长 | 实际应用数据(文本或二进制) |
关键点:
- 客户端发出的帧必须掩码(MASK=1),服务器收到的帧如果未掩码则断开连接。
- 服务器→客户端的帧禁止掩码(MASK=0)。
- 掩码算法:
payload[i] = original[i] XOR maskingKey[i % 4]
六、粘包问题
WebSocket 不会粘包 。因为每个帧头部明确给出了 Payload Len,接收端可以精确切分消息。应用层收到的 receive 回调一定对应一次完整的 send(除非分片帧,但框架已自动重组)。
七、常用控制帧
| 帧类型 | 用途 |
|---|---|
| Close (0x8) | 关闭连接。载荷前 2 字节为状态码(如 1000=正常关闭),后续可跟 UTF-8 原因字符串。 |
| Ping (0x9) | 探测连接存活。接收方必须立即回复 Pong(载荷与 Ping 相同)。 |
| Pong (0xA) | 对 Ping 的响应。 |
八、iOS 开发中的实现
- 官方 API :
URLSessionWebSocketTask(iOS 13+),封装了帧构建、掩码、自动 Ping/Pong 等。 - 无需手撕帧头 ,只需调用
send()、receive()、sendPing()等方法。 - 手动实现(学习/底层控制)时需处理:掩码、载荷长度扩展、字节序转换、分片重组等。
九、典型应用场景
- 即时聊天(微信、QQ、钉钉)
- 实时行情推送(股票、币价)
- 多人协作文档(Google Docs)
- 游戏中的同步指令
- 物联网设备状态上报
十、与其他方案的简单对比
| 方案 | 通信方式 | 实时性 | 开销 | 适用场景 |
|---|---|---|---|---|
| HTTP 轮询 | 客户端周期性请求 | 差(延迟高) | 高 | 低实时性需求 |
| HTTP 长轮询 | 请求挂起直到有新数据 | 较好 | 中 | 兼容老浏览器 |
| SSE | 服务器→客户端单向 | 好 | 低 | 仅需服务器推送(如通知) |
| WebSocket | 全双工实时 | 极好 | 低 | 双向交互场景 |
| TCP Socket 裸写 | 全双工 | 极好 | 最低 | 需要极致控制(但需处理粘包等) |
十一、帧头Frame_head
swift
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
一句话总结
WebSocket 是一种基于 TCP 的全双工持久协议,通过一次 HTTP 握手升级连接,使用轻量帧头传输,天然解决粘包问题,是现代实时双向通信的标准方案。