Page 270 - Web性能权威指南
P. 270
• 操作码(4 位)表示被传输帧的类型:传输应用数据时,是文本(1)还是二进制
(2);连接有效性检查时,是关闭(8)、呼叫(ping,9)还是回应(pong,10)。
• 掩码位表示净荷是否有掩码(只适用于客户端发送给服务器的消息)。
• 净荷长度由可变长度字段表示:
如果是 0~125,就是净荷长度;
如果是 126,则接下来 2 字节表示的 16 位无符号整数才是这一帧的长度;
如果是 127,则接下来 8 字节表示的 64 位无符号整数才是这一帧的长度。
• 掩码键包含 32 位值,用于给净荷加掩护。
• 净荷包含应用数据,如果客户端和服务器在建立连接时协商过,也可以包含自定
义的扩展数据。
所有客户端发送帧的净荷都要使用帧首部中指定的值加掩码,这样可以防
止客户端中运行的恶意脚本对不支持 WebSocket 的中间设备进行缓存投
毒攻击(cache poisoning attack)。要了解这种攻击的细节,请参考 W2SP
2011 的论文“Talking to Yourself for Fun and Profit”(http://w2spconf.com/
2011/papers/websocket.pdf)。
算下来,服务器发送的每个 WebSocket 帧会产生 2~10 字节的分帧开销。而客户端
必须发送掩码键,这又会增加 4 字节,结果就是 6~14 字节的开销。除此之外,没
有其他元数据(比如首部字段或其他关于净荷的信息):所有 WebSocket 通信都是
通过交换帧实现的,而帧将净荷视为不透明的应用数据块。
WebSocket 的多路复用及队首阻塞
WebSocket 很容易发生队首阻塞的情况:消息可能会被分成一或多个帧,但不同
消息的帧不能交错发送,因为没有与 HTTP 2.0 分帧机制中“流 ID”对等的字段
(参见 12.3.2 节“流、消息和帧”)。
显然,如果一个大消息被分成多个 WebSocket 帧,就会阻塞其他消息的帧。如果
你的应用不容许有交付延迟,那可以小心控制每条消息的净荷大小,甚至可以考
虑把大消息拆分成多个小消息!
WebSocket 不支持多路复用,还意味着每个 WebSocket 连接都需要一个专门的
TCP 连接。对于 HTTP 1.x 而言,由于浏览器针对每个来源有连接数量限制,因此
可能会导致问题(参见 11.3 节中的“消耗客户端和服务器资源”)。
好 在,HyBi Working Group 正 着 手 制 定 的 新 的“Multiplexing Extension for
WebSockets”(WebSockets 多路复用扩展)会解决这个问题:
WebSocket | 259