WebSocket帧PAYLOAD_LENGTH为126时EXTENDED_PAYLOAD_LENGTH计算方法
WebSocket负载长度计算(Java实现方案)
结论先行
使用位运算的思路完全正确,是处理WebSocket帧长度解析的标准方案,无需逐位读取,仅按字节读取即可实现。
核心规则说明
引用RFC6455的负载长度定义:
The length of the "Payload data", in bytes: if 0-125, that is the payload length. If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length. If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length.
注意两个关键细节:
- 帧的第二个字节最高位是掩码标识位,计算长度标识时需要取低7位,推荐用
b2 & 0x7F实现,比直接减128更稳妥,不会受Java有符号字节的特性影响 - 扩展长度的字节序为大端序(网络字节序),即先读取的字节为高位,后读取的为低位
双字节扩展长度合并逻辑
当长度标识为126时,第三字节为16位无符号整数的高8位,第四字节为低8位,合并步骤如下:
- 用
& 0xFF将每个有符号byte转换为对应的无符号int值,避免符号位自动补全导致的计算错误 - 将高8位左移8位,放到16位整数的高段位置
- 用按位或运算合并高低8位,得到最终的16位无符号负载长度
对应Java代码如下:
// b3为第三字节,b4为第四字节 int payloadLength = ((b3 & 0xFF) << 8) | (b4 & 0xFF);
完整长度解析示例代码
public long parsePayloadLength(byte[] frameHeader) { // frameHeader至少包含前2个字节,标识为126时至少4字节,127时至少10字节 int payloadLenFlag = frameHeader[1] & 0x7F; if (payloadLenFlag <= 125) { return payloadLenFlag; } else if (payloadLenFlag == 126) { return ((frameHeader[2] & 0xFF) << 8) | (frameHeader[3] & 0xFF); } else { // 127对应8字节扩展长度,用long存储避免溢出 return ((long)(frameHeader[2] & 0xFF) << 56) | ((long)(frameHeader[3] & 0xFF) << 48) | ((long)(frameHeader[4] & 0xFF) << 40) | ((long)(frameHeader[5] & 0xFF) << 32) | ((long)(frameHeader[6] & 0xFF) << 24) | ((long)(frameHeader[7] & 0xFF) << 16) | ((long)(frameHeader[8] & 0xFF) << 8) | (frameHeader[9] & 0xFF); } }
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

