WebSocketHeader详解

发布时间:2023-05-19

WebSocketHeader是WebSocket协议头部的核心组成部分,它包含了协议的版本号、数据帧类型、掩码、负载长度等重要信息。在WebSocket协议通信中,WebSocketHeader扮演了至关重要的角色。本文将围绕WebSocketHeader展开详细阐述,从多个方面对WebSocketHeader进行探讨。

一、WebSocketHeader的组成

WebSocketHeader由6个部分组成,分别是:FIN位、RSV1-3、Opcode、MASK位、Payload length以及Masking Key。下面将分别介绍各个部分的含义。

  1. FIN位:FIN位为1表示当前帧是消息的最后一帧,为0表示消息还有后续帧。实际应用中,由于Websocket协议的限制,消息分片长度通常不得超过16MB。
  2. RSV1-3:RSV位是三个空闲保留位,暂时不用。
  3. Opcode:Opcode指定了当前帧的类型。经过ietf的规定,当前一共定义了Opicde7种类型。分别是:
    • 0x0 - Continuation Frame
    • 0x1 - Text Frame
    • 0x2 - Binary Frame
    • 0x3-7 - Reserved for further non-control frames
    • 0x8 - Close Frame
    • 0x9 - Ping Frame
    • 0xA - Pong Frame
    • 0xB-F - Reserved for further control frames
  4. MASK位:MASK位用于指示负载载荷是否进行了掩码。在通信的时候,客户端发出的数据帧是必须进行掩码处理的,以保证数据的安全性。而服务器返回的数据帧是不能进行掩码处理的。
  5. Payload length:Payload length 表示载荷数据的长度,如果长度在0到125之间,Payload length 所占据的就是一个字节;如果长度是126到65535之间,Payload length 所占据的就是两个字节;而如果长度大于65535 bytes,则所占据的字节为八字节,不过目前这种情况一般都不会发生,所以现在 WebSocket Header 的长度一般都是固定的 2 字节。
  6. Masking Key:4个字节的随机数,被用于对载荷进行加密。在客户端和服务端进行数据通信时,客户端发送数据必须进行加密,而服务端接收到数据时必须进行解密。

二、WebSocketHeader的解析示例

接下来,我们将通过一个示例来解析WebSocketHeader的具体含义。

00000000  81 8C 4D CA 6F F2 1D 1A  EB FC 8C 88 AC E7 1E E5  ..M.o...........
00000010  63 DF 0A 62 60 22 42 80  46 19 90 77 F9 22 16 F9  c..b`"B.F..w."..
00000020  9E 7A 05 B9 C7 92 B3 8D  F1 86 6E 4E 16 0A 2C 3E  .z.........nN..,>

以上代码为WebSocket报文的内容,我们需要进行解析。首先是第一行,由16个字节组成:81是Opcode,表示接下来的内容为文本消息;8C表示Payload length的值,也就是140字节,8C的二进制为 1000 1100,高位比特位表示掩码,低七位表示长度;后面4个字节是Masking Key,这个由服务端发送给客户端的数据包里就有,目的是把掩码用于解密后面的数据;再看后面的内容,就是用Masking Key掩码后的消息。 代码示例

let buffer = Buffer.from([0x81, 0x8C, 0x4D, 0xCA, 0x6F, 0xF2, 0x1D, 0x1A, 0xEB, 0xFC, 0x8C, 0x88, 0xAC, 0xE7, 0x1E, 0xE5, 0x63, 0xDF, 0x0A, 0x62, 0x60, 0x22, 0x42, 0x80, 0x46, 0x19, 0x90, 0x77, 0xF9, 0x22, 0x16, 0xF9, 0x9E, 0x7A, 0x05, 0xB9, 0xC7, 0x92, 0xB3, 0x8D, 0xF1, 0x86, 0x6E, 0x4E, 0x16, 0x0A, 0x2C, 0x3E]);
let FIN = buffer[0] & 0x80;
let Opcode = buffer[0] & 0x0F;
let Mask = buffer[1] & 0x80;
let PayloadLength = buffer[1] & 0x7F;
let Payload = buffer.slice(2, 2 + PayloadLength);
let MaskingKey = buffer.slice(2 + PayloadLength, 2 + PayloadLength + 4);
if (Mask) {
  for (let i = 0; i < PayloadLength; i++) {
    Payload[i] ^= MaskingKey[i % 4];
  }
}
console.log('FIN : ' + FIN);
console.log('Opcode : ' + Opcode);
console.log('Mask : ' + Mask);
console.log('Payload Length : ' + PayloadLength);
console.log('Payload : ' + Payload.toString());
console.log('Masking Key : ' + MaskingKey.toString('hex'));

三、WebSocketHeader的应用场景

WebSocketHeader是在WebSocket协议通信中必不可少的一部分,它通过标识数据类型、数据长度、掩码等信息,保证了WebSocket通信的安全性和实时性。在Web应用中,WebSocket协议已经被广泛应用,例如:在线聊天、消息推送、数据实时更新等。 代码示例

let ws = new WebSocket("wss://www.example.com");
ws.onopen = function() {
  ws.send('Hello World!');
};
ws.onmessage = function(evt) {
  console.log('Received Message: ' + evt.data);
};
ws.onclose = function() {
  console.log('WebSocket closed');
};

四、WebSocketHeader的优化策略

WebSocketHeader的传输开销会调剂一些应用场景下的性能表现。WebSocket协议的通信过程中,如果每次都传输WebSocket Header的全部内容,将极大地影响通信效率。所以,在实际应用中,我们需要针对具体的应用场景,对WebSocketHeader进行优化,以提升通信效率。

  1. Control Frames 压缩 WebSocket协议提供了一些 Control Frames,用于管理连接状态、心跳、关闭连接等。这些帧通常只有几个字节,但由于 WebSocket Header 加载上面,控制帧的大小会比实际负载大几倍,浪费了网络带宽。对控制负载做差异化处理是降低头部的方法之一。
  2. 压缩规划Payload Length 虽然,WebSocket协议 Payload Length 的取值范围巨大,但在实际应用中只有一部分特定长度是需要频繁发送的。协议制定者建议使用 "variable length integers" 的技巧,对 Payload Length 进行经济小巧的编码,来避免头部开销。
  3. Masking Position Internals 在应用中,WebSocket协议无需在所有的数据帧中都应用掩码,开启/关闭掩码的频率取决于应用程序的特定使用场景和需求。尝试将掩码开启/关闭频率最小化。 代码示例
let ws = new WebSocket("wss://www.example.com", {
  perMessageDeflate: {
    zlibDeflateOptions: {
      chunkSize: 1024,
      memLevel: 7,
      level: 3
    },
    zlibInflateOptions: {
      chunkSize: 1024,
    },
    clientNoContextTakeover: true, 
    serverNoContextTakeover: true,
    clientMaxWindowBits: 10, 
    serverMaxWindowBits: 10,
    concurrencyLimit: 10, 
    threshold: 1024 
  }
});
ws.onopen = function() {
  ws.send('Hello World!');
};
ws.onmessage = function(evt) {
  console.log('Received Message: ' + evt.data);
};
ws.onclose = function() {
  console.log('WebSocket closed');
};

五、总结

本文详细阐述了WebSocketHeader的组成、解析、应用场景和优化策略等多个方面。WebSocketHeader作为WebSocket协议通信中的核心组成部分,扮演着至关重要的角色。熟练掌握WebSocketHeader的相关知识,对于优化WebSocket通信效率、提高Web应用性能至关重要。