WebSocket的Frame协议解析

本文深入解析WebSocket帧协议,通过抓包数据详细分析了各字段含义,包括FIN、RSV、OpCode、mask、payloadLen等,并展示了如何解码Masking-key获取原始数据,最终还原出发送的消息内容。

原文链接:https://www.dubby.cn/detail.html?id=9105

先给出WebSocket Frame的协议

image

复制抓包抓到的数据:

81 85 30 6c e2 9a 54 19 80 f8 49

字段分析:

8185306ce29a541980f849
1000000110000101001100000110110011100010100110100101010000011001100000001111100001001001
FIN:1,RSV1-3=0,OpCode=1mask=1,payloadLen=101Masking-keyMasking-keyMasking-keyMasking-keyPayload DataPayload DataPayload DataPayload DataPayload Data
  • FIN=1,说明这是这个消息的最后一个片段,我们这次的消息很短,第一个也就是最后一个
  • RSV1, RSV2, RSV3:分别是1bit,且一般时候都是0
  • OpCode=1(表示是一个text frame)
    • %x0 连续的frame
    • %x1 文本frame
    • %x2 二进制frame
    • %x3-7 预留
    • %x8 连接关闭
    • %x9 ping
    • %xA pong
    • %xB-F 预留
  • 如果mask=1,那么Masking-key存在,且都是4个字节(32位)
  • payloadLen=101(5),说明字节长度是4

最后我们看到数据部分是:

0101010000011001100000001111100001001001
541980f849

掩码解码逻辑:

//掩码
byte[] maskingKeyBytes = {(byte) 0x30, (byte) 0x6c, (byte) 0xe2, (byte) 0x9a};
//掩码编码过得payload
byte[] maskedBytes = {(byte) 0x54, (byte) 0x19, (byte) 0x80, (byte) 0xf8, (byte) 0x49};
int length = maskedBytes.length;
//解码的结果
byte[] unmaskedByte = new byte[length];

for (int i = 0; i < length; ++i) {
    byte masking = maskingKeyBytes[i % 4];
    unmaskedByte[i] = (byte) (maskedBytes[i] ^ masking);
}

for (byte b : unmaskedByte) {
    System.out.print(b + " ");
}

输出:

100 117 98 98 121

转成16进制,正好是

64 75 62 62 79

dubby的utf-8编码后是:

0110010001110101011000100110001001111001
6475626279

没错,我发的消息就是dubby。

<think>好的,我需要帮用户了解TypeScript中WebSocket帧的实现或用法。首先,我应该回顾一下WebSocket的基本概念,然后看看TypeScript如何处理WebSocket,特别是帧的相关操作。 WebSocket协议中,数据是通过帧(frames)传输的,包括文本、二进制、控制帧等。在TypeScript中,通常使用浏览器内置的WebSocket API或者第三方库。但用户可能想知道如何直接处理帧,比如解析或构造帧结构。 首先,浏览器原生的WebSocket API可能不直接暴露帧级别的操作,用户可能需要使用第三方库。例如,可以使用`ws`库在Node.js环境下,或者在浏览器中使用类似`websocket`的库。不过,用户的问题是关于TypeScript的,所以需要确保这些库有TypeScript支持。 接下来,我需要考虑用户可能的实际需求。比如,他们可能想手动处理WebSocket帧来实现自定义协议,或者优化数据传输。这时,可能需要使用到ArrayBuffer或Blob来处理二进制数据,因为WebSocket支持发送和接收二进制帧。 另外,用户可能需要了解如何监听和处理不同的帧类型,比如文本帧、二进制帧、关闭帧等。在TypeScript中,可以通过添加事件监听器来处理这些事件,例如`onmessage`、`onclose`等。 然后,我需要验证一下第三方库的使用方法。例如,`ws`库在Node.js中常用,支持TypeScript,但主要用于服务器端。浏览器端可能需要使用原生的WebSocket对象,或者像`reconnecting-websocket`这样的库来处理重连逻辑。 另外,关于帧的具体结构,RFC 6455定义了WebSocket帧的格式,包括操作码、掩码、负载长度等字段。如果用户需要直接操作这些帧,可能需要手动解析或构建这些二进制数据,这涉及到TypeScript中的类型数组(如Uint8Array)和位操作。 例如,构造一个简单的文本帧,需要设置FIN位、操作码(0x1表示文本帧)、掩码标志和负载数据。在TypeScript中,可能需要使用DataView或位运算符来构造这些字节。 同时,需要注意WebSocket的安全性和协议规范,确保正确实现帧的掩码处理,特别是在客户端到服务器的通信中,客户端必须掩码发送的帧。 最后,我应该提供一些示例代码,展示如何在TypeScript中使用原生WebSocket处理不同帧类型,以及如何通过第三方库进行更底层的操作。同时,提醒用户直接操作帧可能带来的复杂性,建议在必要时才进行这样的底层处理。</think>在 TypeScript 中实现 WebSocket 帧操作通常需要借助第三方库或原生 API 的二进制数据处理能力。以下是关键实现方式和技术细节: ### 1. 原生 WebSocket API 的帧处理 浏览器原生 API 支持通过事件监听处理帧数据,但未直接暴露帧结构解析: ```typescript const socket = new WebSocket('wss://example.com'); // 接收二进制帧(ArrayBuffer格式) socket.binaryType = 'arraybuffer'; socket.onmessage = (event) => { if (event.data instanceof ArrayBuffer) { const buffer = new Uint8Array(event.data); console.log('Received binary frame:', buffer); } else { console.log('Received text frame:', event.data); } }; // 发送二进制帧 const sendBinaryFrame = (data: Uint8Array) => { if (socket.readyState === WebSocket.OPEN) { socket.send(data.buffer); } }; ``` ### 2. 使用 `ws` 库实现帧控制 在 Node.js 环境下,可通过 `ws` 库实现帧级操作(需安装 `@types/ws`)[^2]: ```typescript import WebSocket from 'ws'; const ws = new WebSocket('wss://example.com'); // 接收原始帧数据 ws.on('message', (data, isBinary) => { if (isBinary) { const buffer = Buffer.from(data as Buffer); console.log('Binary frame:', buffer); } }); // 发送分片帧 const sendFragmentedData = () => { ws.send('分段文本第一部分', { fin: false }); ws.send('最后部分', { fin: true }); }; ``` ### 3. 帧结构解析示例 根据 RFC 6455 规范解析帧头(TypeScript 二进制操作): ```typescript function parseFrameHeader(buffer: ArrayBuffer): { opcode: number; payloadLength: number; isFinal: boolean; } { const view = new DataView(buffer); const firstByte = view.getUint8(0); const secondByte = view.getUint8(1); return { isFinal: (firstByte & 0x80) !== 0, opcode: firstByte & 0x0f, payloadLength: secondByte & 0x7f, }; } ``` ### 4. 掩码处理实现 客户端发送帧时需要实现掩码算法: ```typescript function applyMask(payload: Uint8Array, mask: Uint8Array): Uint8Array { const masked = new Uint8Array(payload.length); for (let i = 0; i < payload.length; i++) { masked[i] = payload[i] ^ mask[i % 4]; } return masked; } ``` ### 5. 控制帧处理 实现 ping/pong 保持连接: ```typescript // 发送ping帧 setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.ping(); } }, 30000); // 响应pong ws.on('pong', () => { console.log('Received pong response'); }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值