item->type = type;
item->timestamp = osKernelGetTickCount();
item->in_use = true;
- printf("ws_queue_put type %d , length %d , data %s\n",type,item->length,item->data);
queue->tail = (queue->tail + 1) % WS_QUEUE_SIZE;
queue->count++;
chat_client = init_websocket_client(url_buf, NULL, 1);
if (chat_client != NULL) {
chat_client->msg_queue = &chat_msg_queue;
- chat_client->packet_callback = chat_on_ws_packet_callback;
+ ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+ // chat_client->packet_callback = chat_on_ws_packet_callback;
}
} else {
#ifdef SUPPORT_CHINA_MOBILE_AI_REGULATION
chat_client = init_websocket_client(url_buf, NULL, 0);
if (chat_client != NULL) {
chat_client->msg_queue = &chat_msg_queue;
- chat_client->packet_callback = chat_on_ws_packet_callback;
+ ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+ // chat_client->packet_callback = chat_on_ws_packet_callback;
}
#else
const char* base_url = "ws://118.145.158.207:22080/chat/ws";
chat_client = init_websocket_client(full_url, NULL, 0);
if (chat_client != NULL) {
chat_client->msg_queue = &chat_msg_queue;
- chat_client->packet_callback = chat_on_ws_packet_callback;
+ ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+ // chat_client->packet_callback = chat_on_ws_packet_callback;
}
#endif
}
memset_s(recv_buf, 1024, 0, 1024);
int len = receive_websocket_message_from_queue(&chat_msg_queue, (unsigned char *)recv_buf, 1024, &type, AI_RECEIVE_TIMEOUT_MS);
-
+ if (len < 1024)
+ {
+ recv_buf[len] = '\0';
+ }
if (len == -1 || type == WS_CLOSE) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WebSocket connection closed");
break;
}
AI_UNLOCK();
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "recv_buf %s",recv_buf);
+ if (len < 1024)
+ {
+ recv_buf[len] = '\0';
+ }
chat_result_analysis(recv_buf);
}
}
asr_client = init_websocket_client("ws://118.145.158.207:22080/asr/ws", NULL, 0);
if (asr_client != NULL) {
asr_client->msg_queue = &asr_msg_queue;
- asr_client->packet_callback = asr_on_ws_packet_callback;
+ ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+ // asr_client->packet_callback = asr_on_ws_packet_callback;
}
} else if (g_test_server_index == 2) {
asr_client = init_websocket_client("ws://110.42.224.129:8910/asr/ws", NULL, 0);
if (asr_client != NULL) {
asr_client->msg_queue = &asr_msg_queue;
- asr_client->packet_callback = asr_on_ws_packet_callback;
+ ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+ // asr_client->packet_callback = asr_on_ws_packet_callback;
}
} else {
if (is_raisound_url) {
asr_client = init_websocket_client(url_buf, NULL, 1);
if (asr_client != NULL) {
asr_client->msg_queue = &asr_msg_queue;
- asr_client->packet_callback = asr_on_ws_packet_callback;
+ ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+ // asr_client->packet_callback = asr_on_ws_packet_callback;
}
} else {
asr_client = init_websocket_client("ws://118.145.158.207:22080/asr/ws", NULL, 0);
if (asr_client != NULL) {
asr_client->msg_queue = &asr_msg_queue;
- asr_client->packet_callback = asr_on_ws_packet_callback;
+ ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+ // asr_client->packet_callback = asr_on_ws_packet_callback;
}
}
}
memset_s(asr_recv_buf, 1024, 0, 1024);
int len = receive_websocket_message_from_queue(&asr_msg_queue, (unsigned char *)asr_recv_buf, 1024, &type, AI_RECEIVE_TIMEOUT_MS);
-
+ if (len < 1024)
+ {
+ asr_recv_buf[len] = '\0';
+ }
WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "ASR received: type=%d, len=%d", type, len);
if (type == WS_CLOSE || len == -1) {
tts_client = init_websocket_client(url_buf, NULL, 1);
if (tts_client != NULL) {
tts_client->msg_queue = &tts_msg_queue;
- tts_client->packet_callback = tts_on_ws_packet_callback;
+ ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+ // tts_client->packet_callback = tts_on_ws_packet_callback;
}
} else {
tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512", NULL, 0);
if (tts_client != NULL) {
tts_client->msg_queue = &tts_msg_queue;
- tts_client->packet_callback = tts_on_ws_packet_callback;
+ ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+ // tts_client->packet_callback = tts_on_ws_packet_callback;
}
}
}
// ========== 新增:打印收到的所有原始数据 ==========
- printf("\n=== WebSocket Raw Data Received ===\n");
- printf("Client: %s:%s\n", client->host, client->path);
+ // printf("\n=== WebSocket Raw Data Received ===\n");
+ // printf("Client: %s:%s\n", client->host, client->path);
printf("Total bytes: %zu\n", len);
// printf("Raw data (hex): ");
// // 打印所有数据的十六进制表示
// 使用新的解析器处理当前数据段
int result = ws_parse_stream(parser, current_data, remaining_len);
- if(result == -1)
+ if(result <= 0)
{
printf("ws_process_received_data: parsing error, reset parser,find next frame. Remaining: %zu bytes\n", remaining_len);
ws_parser_reset(parser);
if (header && payload) {
printf("WebSocket frame received: opcode=0x%02X, fin=%d, payload_len=%llu\n",
header->opcode, header->fin, header->payload_len);
+ // printf("payload = %s\n",payload);
// 打印载荷数据的前几个字节(用于调试)
- if (payload_len > 0) {
- printf("Payload data (first 32 bytes): ");
- for (size_t i = 0; i < payload_len && i < 32; i++) {
- printf("%02X ", payload[i]);
- }
- if (payload_len > 32) printf("...");
- printf("\n");
- }
+ // if (payload_len > 0) {
+ // printf("Payload data (first 32 bytes): ");
+ // for (size_t i = 0; i < payload_len && i < 32; i++) {
+ // printf("%02X ", payload[i]);
+ // }
+ // if (payload_len > 32) printf("...");
+ // printf("\n");
+ // }
// 根据操作码处理不同类型的消息
switch (header->opcode) {
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
-#include "wearable_log.h"
+
+// 控制日志输出的宏
+#define ENABLE_DEBUG_LOG 1 // 设置为0可以关闭所有调试输出
+
+#if ENABLE_DEBUG_LOG
+#define WS_LOG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
+#define WS_LOGI(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOGD(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOGE(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__)
+#else
+#define WS_LOG(fmt, ...)
+#define WS_LOGI(fmt, ...)
+#define WS_LOGD(fmt, ...)
+#define WS_LOGE(fmt, ...)
+#endif
#ifdef __cplusplus
extern "C" {
/*
* WebSocket协议解析器 (RFC 6455)
- *
- * WebSocket单帧大小限制说明:
- *
- * 1. 协议层面限制:
- * - 16位长度字段:最大 65,535 字节 (2^16 - 1)
- * - 64位长度字段:最大 18,446,744,073,709,551,615 字节 (2^64 - 1)
- *
- * 2. 控制帧限制(RFC 6455规定):
- * - Ping/Pong帧:最大125字节负载
- * - Close帧:最大125字节负载
- *
- * 3. 应用层限制:
- * - 默认最大负载长度:65,535字节(16位)
- * - 可配置最大负载长度:最大1MB
- * - 可通过 ws_set_max_payload_length() 函数动态配置
- *
- * 4. 实际限制因素:
- * - 内存限制
- * - 网络MTU限制
- * - 应用层缓冲区大小
- * - 浏览器/客户端实现限制
*/
// WebSocket帧类型枚举
// 初始化WebSocket解析器
ws_parser_t* ws_parser_init() {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Initializing WebSocket parser");
+ WS_LOGI("WS: Initializing WebSocket parser");
ws_parser_t* parser = (ws_parser_t*)malloc(sizeof(ws_parser_t));
if (!parser) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Failed to allocate memory for parser");
+ WS_LOGE("WS: Failed to allocate memory for parser");
return NULL;
}
// 初始化全局缓存
if (!g_ws_buffer) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Allocating global buffer (%d bytes)", WS_BUFFER_SIZE);
+ WS_LOGI("WS: Allocating global buffer (%d bytes)", WS_BUFFER_SIZE);
g_ws_buffer = (uint8_t*)malloc(WS_BUFFER_SIZE);
if (!g_ws_buffer) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Failed to allocate global buffer");
+ WS_LOGE("WS: Failed to allocate global buffer");
free(parser);
return NULL;
}
}
g_parser_count++;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parser count: %d", g_parser_count);
+ WS_LOGI("WS: Parser count: %d", g_parser_count);
// 初始化解析器状态
parser->state = WS_STATE_START;
parser->mask_pos = 0;
memset(&parser->header, 0, sizeof(ws_header_t));
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parser initialized successfully");
+ WS_LOGI("WS: Parser initialized successfully");
return parser;
}
void ws_parser_reset(ws_parser_t* parser) {
if (!parser) return;
- // WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Resetting parser state");
-
parser->state = WS_STATE_START;
parser->buffer_pos = 0;
parser->payload_remaining = 0;
// 配置最大负载长度
int ws_set_max_payload_length(uint64_t max_len) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Setting max payload length to %llu bytes", (unsigned long long)max_len);
+ WS_LOGI("WS: Setting max payload length to %llu bytes", (unsigned long long)max_len);
if (max_len > WS_MAX_PAYLOAD_LEN_MAX) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Max payload length %llu exceeds limit %llu",
+ WS_LOGE("WS: Max payload length %llu exceeds limit %llu",
(unsigned long long)max_len, (unsigned long long)WS_MAX_PAYLOAD_LEN_MAX);
return 0; // 超过最大允许值
}
if (max_len < 1) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Invalid max payload length: %llu (must be >= 1)", (unsigned long long)max_len);
+ WS_LOGE("WS: Invalid max payload length: %llu (must be >= 1)", (unsigned long long)max_len);
return 0; // 不能小于1字节
}
g_max_payload_len = max_len;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Max payload length set successfully");
+ WS_LOGI("WS: Max payload length set successfully");
return 1;
}
case WS_STATE_START:
parser->state = WS_STATE_READ_HEADER1;
// 继续执行,处理第一个字节
- // 注意:这里故意不break,让代码继续执行
case WS_STATE_READ_HEADER1:{
// 解析第一个头部字节
parser->header.rsv3 = (byte >> 4) & 0x1;
parser->header.opcode = (ws_opcode_t)(byte & 0x0F);
-
-
-
- // WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parse header1 - FIN:%d, RSV:%d%d%d, OPCODE:0x%02X",
- // parser->header.fin, parser->header.rsv1, parser->header.rsv2, parser->header.rsv3, parser->header.opcode);
-
-
// 检查 opcode 是否有效
if (!((parser->header.opcode >= WS_CONTINUATION && parser->header.opcode <= WS_BINARY) ||
(parser->header.opcode >= WS_CLOSE && parser->header.opcode <= WS_PONG))) {
- // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Invalid opcode: 0x%02X", parser->header.opcode);
+ WS_LOGE("WS: Invalid opcode: 0x%02X", parser->header.opcode);
parser->state = WS_STATE_ERROR;
return -1;
}
- if(parser->header.fin == 0)
- {
- // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Invalid FIN bit: %d", parser->header.fin);
- // parser->state = WS_STATE_ERROR;
- // return -1;
- }
// 检查RSV位是否都为0(根据RFC6455规范)
- if (parser->header.rsv1 || parser->header.rsv2 || parser->header.rsv3) {
- // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Invalid RSV bits: %d%d%d",
- // parser->header.rsv1, parser->header.rsv2, parser->header.rsv3);
- // parser->state = WS_STATE_ERROR;
- // return -1;
+ if (!(parser->header.fin == 1 && parser->header.rsv1 == 0 && parser->header.rsv2 == 0 && parser->header.rsv3 == 0))
+ {
+ WS_LOGE("WS: Invalid RSV bits: %d%d%d",
+ parser->header.rsv1, parser->header.rsv2, parser->header.rsv3);
+ parser->state = WS_STATE_ERROR;
+ return -1;
}
+ WS_LOGD("WS: Parse header1 - FIN:%d, RSV:%d%d%d, OPCODE:0x%02X",
+ parser->header.fin, parser->header.rsv1, parser->header.rsv2, parser->header.rsv3, parser->header.opcode);
+
+
+
// 保存第一个头部字节到缓存
if (parser->buffer_pos < WS_BUFFER_SIZE) {
parser->buffer[parser->buffer_pos++] = byte;
} else {
parser->state = WS_STATE_ERROR;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow in header1");
+ WS_LOGE("WS: Buffer overflow in header1");
return -1;
}
parser->header.mask = (byte >> 7) & 0x1;
uint8_t payload_len = byte & 0x7F;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "WS: Parse header2 - MASK:%d, LEN:%d",
+ WS_LOGD("WS: Parse header2 - MASK:%d, LEN:%d",
parser->header.mask, payload_len);
// 保存第二个头部字节到缓存
parser->buffer[parser->buffer_pos++] = byte;
} else {
parser->state = WS_STATE_ERROR;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow in header2");
+ WS_LOGE("WS: Buffer overflow in header2");
return -1;
}
parser->header.payload_len = payload_len;
parser->payload_remaining = payload_len;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Small payload length: %d bytes", payload_len);
+ WS_LOGI("WS: Small payload length: %d bytes", payload_len);
// 验证控制帧长度
if (!validate_control_frame_length(parser->header.opcode, payload_len)) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Control frame length validation failed: opcode=0x%02X, len=%d",
+ WS_LOGE("WS: Control frame length validation failed: opcode=0x%02X, len=%d",
parser->header.opcode, payload_len);
parser->state = WS_STATE_ERROR;
return -1;
}
} else if (payload_len == 126) {
// 16位长度,需要再读取2个字节
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Extended 16-bit payload length mode");
+ WS_LOGI("WS: Extended 16-bit payload length mode");
parser->header.payload_len = 126; // 临时标记
parser->payload_remaining = 2;
parser->state = WS_STATE_READ_PAYLOAD_LEN;
} else if (payload_len == 127) {
// 64位长度,需要再读取8个字节
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Extended 64-bit payload length mode");
+ WS_LOGI("WS: Extended 64-bit payload length mode");
parser->header.payload_len = 127; // 临时标记
parser->payload_remaining = 8;
parser->state = WS_STATE_READ_PAYLOAD_LEN;
}
case WS_STATE_READ_PAYLOAD_LEN: {
- // 保存长度字节到缓存
- if (parser->buffer_pos < WS_BUFFER_SIZE) {
- parser->buffer[parser->buffer_pos++] = byte;
- } else {
- parser->state = WS_STATE_ERROR;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow in payload length");
- return -1;
- }
+ // // 保存长度字节到缓存
+ // if (parser->buffer_pos < WS_BUFFER_SIZE) {
+ // parser->buffer_pos++;
+ // } else {
+ // parser->state = WS_STATE_ERROR;
+ // WS_LOGE("WS: Buffer overflow in payload length");
+ // return -1;
+ // }
- // 累加长度数据 - 修复:使用正确的索引计算
+ // 累加长度数据
static uint8_t len_bytes[8];
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "WS: Reading payload length byte: 0x%02X, remaining: %zu",
+ WS_LOGD("WS: Reading payload length byte: 0x%02X, remaining: %zu",
byte, parser->payload_remaining);
-
+
if (parser->header.payload_len == 126) {
// 16位扩展长度:只需要2个字节
// 第一个字节存储在len_bytes[0],第二个字节存储在len_bytes[1]
parser->payload_remaining--;
if (parser->payload_remaining == 0) {
- // 计算16位长度 - 修复:使用正确的字节顺序
- // 注意:网络字节序是大端序,第一个字节是高字节
- parser->header.payload_len = (len_bytes[0] << 8) | len_bytes[1];
- parser->payload_remaining = parser->header.payload_len;
+ // 计算16位长度
+ uint16_t _payload_len = (uint16_t)(len_bytes[0] <<8 ) + len_bytes[1];
+ printf("len_bytes[0] = %d, len_bytes[1] = %d\n ,payload_len = %d\n", len_bytes[0], len_bytes[1],_payload_len);
+
+ parser->header.payload_len = _payload_len;
+ parser->payload_remaining = _payload_len;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: 16-bit payload length: %d bytes (0x%02X%02X)",
- parser->header.payload_len, len_bytes[0], len_bytes[1]);
+ WS_LOGI("WS: 16-bit payload length: %d bytes (0x%02X%02X)",
+ parser->header.payload_len, len_bytes[1], len_bytes[0]);
// 验证控制帧长度
if (!validate_control_frame_length(parser->header.opcode, parser->header.payload_len)) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Control frame length validation failed for 16-bit length");
+ WS_LOGE("WS: Control frame length validation failed for 16-bit length");
parser->state = WS_STATE_ERROR;
return -1;
}
// 检查负载长度是否合理
if (parser->header.payload_len > g_max_payload_len) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Payload length %d exceeds maximum %llu",
+ WS_LOGE("WS: Payload length %d exceeds maximum %llu",
parser->header.payload_len, (unsigned long long)g_max_payload_len);
parser->state = WS_STATE_ERROR;
return -1;
// 检查缓存是否足够
if (parser->buffer_pos + parser->header.payload_len > WS_BUFFER_SIZE) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow: current=%zu, adding=%d, max=%d",
+ WS_LOGE("WS: Buffer overflow: current=%zu, adding=%d, max=%d",
parser->buffer_pos, parser->header.payload_len, WS_BUFFER_SIZE);
parser->state = WS_STATE_ERROR;
return -1;
// 处理掩码
if (parser->header.mask) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Moving to READ_MASK state");
+ WS_LOGI("WS: Moving to READ_MASK state");
parser->state = WS_STATE_READ_MASK;
} else {
if (parser->payload_remaining == 0) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Zero payload, moving to COMPLETE state");
+ WS_LOGI("WS: Zero payload, moving to COMPLETE state");
parser->state = WS_STATE_COMPLETE;
return 1;
}
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Moving to READ_PAYLOAD state");
+ WS_LOGI("WS: Moving to READ_PAYLOAD state");
parser->state = WS_STATE_READ_PAYLOAD;
}
}
} else if (parser->header.payload_len == 127) {
// 64位扩展长度:需要8个字节
- // 使用正确的索引:从0开始,按顺序存储
size_t byte_index = 8 - parser->payload_remaining;
len_bytes[byte_index] = byte;
}
parser->payload_remaining = parser->header.payload_len;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: 64-bit payload length: %llu bytes",
+ WS_LOGI("WS: 64-bit payload length: %llu bytes",
(unsigned long long)parser->header.payload_len);
// 验证控制帧长度
if (!validate_control_frame_length(parser->header.opcode, parser->header.payload_len)) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Control frame length validation failed for 64-bit length");
+ WS_LOGE("WS: Control frame length validation failed for 64-bit length");
parser->state = WS_STATE_ERROR;
return -1;
}
// 检查负载长度是否合理
if (parser->header.payload_len > g_max_payload_len) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: 64-bit payload length %llu exceeds maximum %llu",
- parser->header.payload_len, (unsigned long long)g_max_payload_len);
+ WS_LOGE("WS: Payload length %llu exceeds maximum %llu",
+ (unsigned long long)parser->header.payload_len, (unsigned long long)g_max_payload_len);
parser->state = WS_STATE_ERROR;
return -1;
}
// 检查缓存是否足够
if (parser->buffer_pos + parser->header.payload_len > WS_BUFFER_SIZE) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow: current=%zu, adding=%llu, max=%d",
- parser->buffer_pos, parser->header.payload_len, WS_BUFFER_SIZE);
+ WS_LOGE("WS: Buffer overflow: current=%zu, adding=%llu, max=%d",
+ parser->buffer_pos, (unsigned long long)parser->header.payload_len, WS_BUFFER_SIZE);
parser->state = WS_STATE_ERROR;
return -1;
}
// 处理掩码
if (parser->header.mask) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Moving to READ_MASK state");
+ WS_LOGI("WS: Moving to READ_MASK state");
parser->state = WS_STATE_READ_MASK;
+ return 1;
} else {
if (parser->payload_remaining == 0) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Zero payload, moving to COMPLETE state");
+ WS_LOGI("WS: Zero payload, moving to COMPLETE state");
parser->state = WS_STATE_COMPLETE;
return 1;
}
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Moving to READ_PAYLOAD state");
+ WS_LOGI("WS: Moving to READ_PAYLOAD state");
parser->state = WS_STATE_READ_PAYLOAD;
}
}
break;
}
- case WS_STATE_READ_MASK:
+ case WS_STATE_READ_MASK: {
// 读取掩码密钥
- parser->header.mask_key[parser->mask_pos++] = byte;
-
- // 保存掩码字节到缓存
+ if (parser->mask_pos < 4) {
+ parser->header.mask_key[parser->mask_pos++] = byte;
+ // 保存掩码字节到缓存
if (parser->buffer_pos < WS_BUFFER_SIZE) {
parser->buffer[parser->buffer_pos++] = byte;
} else {
parser->state = WS_STATE_ERROR;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow in mask");
+ WS_LOGI("WS: Buffer overflow in mask");
return -1;
}
// 掩码密钥共4字节
- if (parser->mask_pos == 4) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Mask key read: %02X %02X %02X %02X",
- parser->header.mask_key[0], parser->header.mask_key[1],
- parser->header.mask_key[2], parser->header.mask_key[3]);
-
- if (parser->payload_remaining == 0) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Frame parsing complete (zero payload)");
- parser->state = WS_STATE_COMPLETE;
- return 1;
+ if (parser->mask_pos == 4) {
+ WS_LOGI("WS: Mask key read complete: 0x%02X%02X%02X%02X",
+ parser->header.mask_key[0], parser->header.mask_key[1],
+ parser->header.mask_key[2], parser->header.mask_key[3]);
+
+ if (parser->payload_remaining == 0) {
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ parser->state = WS_STATE_READ_PAYLOAD;
}
- parser->state = WS_STATE_READ_PAYLOAD;
}
break;
+ }
case WS_STATE_READ_PAYLOAD: {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "WS: Reading payload byte, remaining: %zu, buffer_pos: %zu",
- parser->payload_remaining, parser->buffer_pos);
-
- // 保存负载字节到缓存
+ // 读取负载数据
if (parser->buffer_pos < WS_BUFFER_SIZE) {
parser->buffer[parser->buffer_pos++] = byte;
+ parser->payload_remaining--;
+
+ if (parser->payload_remaining == 0) {
+ // 负载读取完成
+ WS_LOGI("WS: Payload read complete (%zu bytes)", parser->header.payload_len);
+
+ // 如果有掩码,应用掩码解码
+ if (parser->header.mask) {
+ // 计算负载在缓存中的起始位置
+ size_t payload_start = parser->buffer_pos - parser->header.payload_len;
+ apply_mask(parser->buffer + payload_start, parser->header.payload_len,
+ parser->header.mask_key, 0);
+ WS_LOGI("WS: Mask applied to payload");
+ }
+
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
} else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Buffer overflow in payload reading");
parser->state = WS_STATE_ERROR;
+ WS_LOGE("WS: Buffer overflow in payload");
return -1;
}
-
- parser->payload_remaining--;
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "WS: After reading byte, remaining: %zu, buffer_pos: %zu",
- parser->payload_remaining, parser->buffer_pos);
-
- // 所有负载都已读取
- if (parser->payload_remaining == 0) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Payload read complete (%llu bytes)",
- (unsigned long long)parser->header.payload_len);
-
- // 如果有掩码,对负载数据进行解码
- if (parser->header.mask) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Applying mask to payload data");
- size_t payload_start = parser->buffer_pos - parser->header.payload_len;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Payload start: %zu, payload length: %llu",
- payload_start, parser->header.payload_len);
- apply_mask(parser->buffer + payload_start,
- parser->header.payload_len,
- parser->header.mask_key,
- 0);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Frame parsing complete, transitioning to COMPLETE state");
- parser->state = WS_STATE_COMPLETE;
- return 1;
- }
break;
}
+ case WS_STATE_COMPLETE:
+ WS_LOGI("WS: Frame parsing complete, transitioning to COMPLETE state");
+ return 1;
+
+ case WS_STATE_ERROR:
+ WS_LOGE("WS: Parser is in error state");
+ return -1;
+
default:
- break;
+ WS_LOGE("WS: Unknown parser state: %d", parser->state);
+ parser->state = WS_STATE_ERROR;
+ return -1;
}
- return 0;
+ return 0; // 继续解析
}
-// 处理流数据输入
-// 返回值:解析出的完整包长度,0-未完成,-1-错误
+// 解析数据流
int ws_parse_stream(ws_parser_t* parser, const uint8_t* data, size_t len) {
if (!parser || !data || len == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Invalid parameters for stream parsing");
+ WS_LOGE("WS: Invalid parameters for ws_parse_stream");
return -1;
}
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parsing stream data (%zu bytes), current state: %d, buffer_pos: %zu",
- len, parser->state, parser->buffer_pos);
+ WS_LOGI("WS: Parsing stream data (%zu bytes), current state: %d, buffer_pos: %zu",
+ len, parser->state, parser->buffer_pos);
- // 重要:如果解析器状态为COMPLETE,说明上一个帧已经完成
- // 新数据应该开始解析新的帧,需要重置解析器状态
+ // 如果解析器已经完成一个帧,重置状态
if (parser->state == WS_STATE_COMPLETE) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parser was in COMPLETE state, resetting for new frame");
+ WS_LOGI("WS: Parser was in COMPLETE state, resetting for new frame");
ws_parser_reset(parser);
}
- size_t i=0;
- for (i = 0; i < len; i++) {
+
+ int total_processed = 0;
+
+ for (size_t i = 0; i < len; i++) {
int result = ws_parse_byte(parser, data[i]);
if (result == 1) {
- // 解析完成一个包
- int packet_len = parser->buffer_pos;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Complete frame parsed (%d bytes total) opcode: %d, payload_len: %llu",
- packet_len, parser->header.opcode, parser->header.payload_len);
-
- // 重要:不要在这里重置解析器!
- // 让上层处理完数据后再调用 ws_parser_reset()
- // 这样可以确保数据被正确处理后再清理状态
- return i+1;
+ // 帧解析完成
+ WS_LOGI("WS: Complete frame parsed (%zu bytes total) opcode: %d, payload_len: %llu",
+ parser->buffer_pos, parser->header.opcode, (unsigned long long)parser->header.payload_len);
+ total_processed = i + 1;
+ break;
} else if (result == -1) {
- // 解析错误,重置解析器
- // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Parse error at byte %zu, resetting parser, byte: %02X", i, data[i]);
+ // 解析错误
+ WS_LOGE("WS: Parsing error at byte %zu", i);
ws_parser_reset(parser);
- continue;
+ // return -1;
+ total_processed = i + 1;
}
+ // result == 0 继续解析
}
- // 未完成解析,显示当前状态信息
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Frame parsing incomplete, waiting for more data. State: %d, Buffer: %zu/%zu, Payload remaining: %zu",
- parser->state, parser->buffer_pos, WS_BUFFER_SIZE, parser->payload_remaining);
- return i+1;
+ if (parser->state == WS_STATE_COMPLETE) {
+ WS_LOGI(" WS_STATE_COMPLETE at %d\n",total_processed);
+ } else if (parser->state == WS_STATE_ERROR) {
+ WS_LOGI(" WS_STATE_ERROR at %d\n",total_processed);
+ } else {
+ // 数据不完整,继续等待更多数据
+ WS_LOGI("WS: Frame parsing incomplete, waiting for more data. State: %d, Buffer: %zu/%d, Payload remaining: %zu",
+ parser->state, parser->buffer_pos, WS_BUFFER_SIZE, parser->payload_remaining);
+ }
+ return total_processed;
}
-// 新增:打印解析器详细状态信息(用于调试)
-void ws_parser_debug_state(ws_parser_t* parser) {
- if (!parser) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Cannot debug NULL parser");
- return;
+// 获取解析出的头部信息
+const ws_header_t* ws_get_header(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
+ }
+ return &parser->header;
+}
+
+// 获取完整数据包(包含帧头)
+const uint8_t* ws_get_packet(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
+ }
+ return parser->buffer;
+}
+
+// 获取纯载荷数据
+const uint8_t* ws_get_payload(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
}
- const char* state_names[] = {
- "START", "READ_HEADER1", "READ_HEADER2", "READ_PAYLOAD_LEN",
- "READ_MASK", "READ_PAYLOAD", "COMPLETE", "ERROR"
- };
+ // 计算载荷数据的起始位置
+ // 帧头:2字节(基本头部)
+ size_t header_size = 2;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parser Debug State:");
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " State: %s (%d)",
- state_names[parser->state], parser->state);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Buffer Position: %zu/%d",
- parser->buffer_pos, WS_BUFFER_SIZE);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Payload Remaining: %zu",
- parser->payload_remaining);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Mask Position: %zu",
- parser->mask_pos);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Header Info:");
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " FIN: %d", parser->header.fin);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Opcode: 0x%02X", parser->header.opcode);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Mask: %d", parser->header.mask);
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Payload Length: %llu",
- (unsigned long long)parser->header.payload_len);
+ // 扩展长度字段
+ if (parser->header.payload_len == 126) {
+ header_size += 2; // 16位长度
+ } else if (parser->header.payload_len == 127) {
+ header_size += 8; // 64位长度
+ }
+ // 掩码密钥
if (parser->header.mask) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Mask Key: %02X %02X %02X %02X",
- parser->header.mask_key[0], parser->header.mask_key[1],
- parser->header.mask_key[2], parser->header.mask_key[3]);
+ header_size += 4;
}
- // 打印缓冲区前几个字节(用于调试)
- if (parser->buffer_pos > 0) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, " Buffer (first 16 bytes):");
- for (size_t i = 0; i < parser->buffer_pos && i < 16; i++) {
- printf("%02X ", parser->buffer[i]);
- }
- if (parser->buffer_pos > 16) printf("...");
- printf("\n");
+ // 检查载荷数据是否在缓存范围内
+ if (header_size + parser->header.payload_len > parser->buffer_pos) {
+ WS_LOGE("WS: Payload start position %zu exceeds buffer size %zu", header_size, parser->buffer_pos);
+ return NULL;
}
+
+ return parser->buffer + header_size;
}
-// 新增:手动重置解析器状态(供上层调用)
-void ws_parser_manual_reset(ws_parser_t* parser) {
- if (!parser) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "WS: Attempt to manually reset NULL parser");
- return;
+// 获取载荷数据长度
+size_t ws_get_payload_length(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return 0;
}
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Manual parser reset requested");
- ws_parser_reset(parser);
+ return parser->header.payload_len;
+}
+
+// 检查解析器是否有错误
+int ws_parser_has_error(ws_parser_t* parser) {
+ return (parser && parser->state == WS_STATE_ERROR) ? 1 : 0;
}
-// 释放解析器资源
+// 获取解析器当前状态
+ws_parse_state_t ws_parser_get_state(ws_parser_t* parser) {
+ return parser ? parser->state : WS_STATE_ERROR;
+}
+
+// 销毁解析器
void ws_parser_destroy(ws_parser_t* parser) {
if (parser) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Destroying WebSocket parser");
free(parser);
g_parser_count--;
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Parser count after destroy: %d", g_parser_count);
-
- // 只有当没有解析器实例时才释放全局缓存
+ // 如果所有解析器都被销毁,释放全局缓存
if (g_parser_count == 0 && g_ws_buffer) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Releasing global buffer (last parser destroyed)");
free(g_ws_buffer);
g_ws_buffer = NULL;
+ WS_LOGI("WS: Global buffer freed");
}
- } else {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "WS: Attempt to destroy NULL parser");
+
+ WS_LOGI("WS: Parser destroyed, remaining parsers: %d", g_parser_count);
}
}
-// 获取解析出的头部信息
-const ws_header_t* ws_get_header(ws_parser_t* parser) {
- if (!parser) return NULL;
- return &parser->header;
-}
-
-// 获取解析出的完整数据包(包含帧头,用于调试)
-const uint8_t* ws_get_packet(ws_parser_t* parser) {
- if (!parser) return NULL;
- return parser->buffer;
+#ifdef __cplusplus
}
-
-// 新增:获取纯载荷数据(不包含帧头)
-const uint8_t* ws_get_payload(ws_parser_t* parser) {
- if (!parser || parser->state != WS_STATE_COMPLETE) return NULL;
+#endif
+#if 0
+// 多包拆解测试函数
+void test_multiple_frames() {
+ printf("\n=== Multiple WebSocket Frames Test ===\n");
- // 计算载荷数据的起始位置
- size_t payload_start = 0;
+ // 测试数据:包含多个WebSocket帧
+ uint8_t test_data[] = {
+ // 第一个帧:5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第二个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 E6 A0 B7 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ 0x99, 0xE6, 0xA0, 0xB7, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第三个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 9A 84 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 74, 0x22, 0x3A, 0x22, 0xE7, 0x9A,
+ 0x84, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第四个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 95 B0 E5 AD 97 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x95,
+ 0xB0, 0xE5, 0xAD, 0x97, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第五个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 BB 84 E5 90 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE7, 0xBB,
+ 0x84, 0xE5, 0x90, 0x88, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第六个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 91 A2 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x91,
+ 0xA2, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第七个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E3 80 82 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE3, 0x80,
+ 0x82, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第八个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE4, 0xBD,
+ 0xA0, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第九个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 83 BD 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0x83,
+ 0xBD, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 AF B4 E8 AF B4 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xAF,
+ 0xB4, 0xE8, 0xAF, 0xB4, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十一个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ 0x99, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十二个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 87 A0 E4 B8 AA 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x87,
+ 0xA0, 0xE4, 0xB8, 0xAA, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十三个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 95 B0 E5 AD 97 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x95,
+ 0xB0, 0xE5, 0xAD, 0x97, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十四个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 98 AF 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x98,
+ 0xAF, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十五个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 9C A8 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x9C,
+ 0xA8, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D
+ };
- // 基本头部:2字节
- payload_start += 2;
+ size_t test_data_len = sizeof(test_data);
- // 扩展长度字段
- uint8_t payload_len_initial = parser->buffer[1] & 0x7F;
- if (payload_len_initial == 126) {
- payload_start += 2; // 16位长度
- } else if (payload_len_initial == 127) {
- payload_start += 8; // 64位长度
+ printf("Test data length: %zu bytes\n", test_data_len);
+ printf("Test data (hex): ");
+ for (size_t i = 0; i < test_data_len; i++) {
+ printf("%02X ", test_data[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
}
+ printf("\n");
- // 掩码密钥(如果存在)
- if (parser->header.mask) {
- payload_start += 4;
+ // 创建解析器
+ ws_parser_t* parser = ws_parser_init();
+ if (!parser) {
+ printf("Failed to create parser\n");
+ return;
}
- // 确保不越界
- if (payload_start >= parser->buffer_pos) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "WS: Payload start position %zu exceeds buffer size %zu",
- payload_start, parser->buffer_pos);
- return NULL;
- }
+ // 多包拆解测试
+ printf("\n=== Starting Multi-Frame Parsing ===\n");
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WS: Payload data starts at offset %zu, length %llu",
- payload_start, parser->header.payload_len);
+ size_t offset = 0;
+ int frame_count = 0;
- return parser->buffer + payload_start;
-}
+ while (offset < test_data_len) {
+ printf("\n--- Frame %d ---\n", frame_count + 1);
+ printf("Remaining data: %zu bytes\n", test_data_len - offset);
+
+ // 解析当前帧
+ int result = ws_parse_stream(parser, test_data + offset, test_data_len - offset);
+ ws_parse_state_t ws_state = ws_parser_get_state(parser);
+ printf("ws_state: %d,result: %d\n", ws_state,result);
+ if (result > 0 && ws_state == WS_STATE_COMPLETE) {
+ frame_count++;
+ printf("Frame %d parsed successfully, consumed %d bytes\n", frame_count, result);
+
+ const ws_header_t* header = ws_get_header(parser);
+ if (header) {
+ printf("Frame header:\n");
+ printf(" FIN: %d\n", header->fin);
+ printf(" RSV: %d%d%d\n", header->rsv1, header->rsv2, header->rsv3);
+ printf(" Opcode: 0x%02X\n", header->opcode);
+ printf(" Mask: %d\n", header->mask);
+ printf(" Payload length: %llu\n", (unsigned long long)header->payload_len);
+
+ if (header->mask) {
+ printf(" Mask key: 0x%02X%02X%02X%02X\n",
+ header->mask_key[0], header->mask_key[1],
+ header->mask_key[2], header->mask_key[3]);
+ }
+ }
+
+ const uint8_t* payload = ws_get_payload(parser);
+ size_t payload_len = ws_get_payload_length(parser);
+
+ if (payload && payload_len > 0) {
+ printf("Payload data:\n");
+ printf(" Length: %zu bytes\n", payload_len);
+ printf(" Hex: ");
+ for (size_t i = 0; i < payload_len && i < 32; i++) {
+ printf("%02X ", payload[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ if (payload_len > 32) printf("...");
+ printf("\n");
+
+ printf(" ASCII: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ if (payload[i] >= 32 && payload[i] <= 126) {
+ printf("%c", payload[i]);
+ } else {
+ printf(".");
+ }
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+ }
+
+
+
+ // 重置解析器状态,准备解析下一个帧
+ ws_parser_reset(parser);
+
+ } else if (result > 0 && ws_state != WS_STATE_ERROR) {
+ printf("Parser state: %d reset \n", ws_parser_get_state(parser));
+ // 重置解析器状态,准备解析下一个帧
+ ws_parser_reset(parser);
+ } else {
+ printf("Incomplete frame, need more data\n");
+ // printf("Parse error at offset %zu\n", offset);
+ // printf("Parser state: %d\n", ws_parser_get_state(parser));
+ }
-// 新增:获取载荷数据长度
-size_t ws_get_payload_length(ws_parser_t* parser) {
- if (!parser || parser->state != WS_STATE_COMPLETE) return 0;
- return parser->header.payload_len;
+ // 移动到下一个帧
+ offset += result;
+ // 添加安全检查
+ if (offset >= test_data_len) {
+ printf("Reached end of data\n");
+ break;
+ }
+ }
+
+ printf("\n=== Multi-Frame Parsing Complete ===\n");
+ printf("Total frames parsed: %d\n", frame_count);
+ printf("Total bytes processed: %zu\n", offset);
+ printf("Remaining bytes: %zu\n", test_data_len - offset);
+
+ // 清理
+ ws_parser_destroy(parser);
}
-// 新增:检查解析器是否处于错误状态
-int ws_parser_has_error(ws_parser_t* parser) {
- if (!parser) return 1;
- return (parser->state == WS_STATE_ERROR);
+// 单帧测试函数(保留原有功能)
+void test_single_frame() {
+ printf("\n=== Single WebSocket Frame Test ===\n");
+
+ // 测试数据:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 E6 A0 B7 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ uint8_t test_data[] = {
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ 0x99, 0xE6, 0xA0, 0xB7, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D
+ };
+
+ size_t test_data_len = sizeof(test_data);
+
+ printf("Test data length: %zu bytes\n", test_data_len);
+ printf("Test data (hex): ");
+ for (size_t i = 0; i < test_data_len; i++) {
+ printf("%02X ", test_data[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ printf("\n");
+
+ // 创建解析器
+ ws_parser_t* parser = ws_parser_init();
+ if (!parser) {
+ printf("Failed to create parser\n");
+ return;
+ }
+
+ // 解析数据
+ int result = ws_parse_stream(parser, test_data, test_data_len);
+
+ if (result > 0) {
+ printf("\n=== Parse Result ===\n");
+ printf("Parsed bytes: %d\n", result);
+
+ const ws_header_t* header = ws_get_header(parser);
+ if (header) {
+ printf("Frame header:\n");
+ printf(" FIN: %d\n", header->fin);
+ printf(" RSV: %d%d%d\n", header->rsv1, header->rsv2, header->rsv3);
+ printf(" Opcode: 0x%02X\n", header->opcode);
+ printf(" Mask: %d\n", header->mask);
+ printf(" Payload length: %llu\n", (unsigned long long)header->payload_len);
+
+ if (header->mask) {
+ printf(" Mask key: 0x%02X%02X%02X%02X\n",
+ header->mask_key[0], header->mask_key[1],
+ header->mask_key[2], header->mask_key[3]);
+ }
+ }
+
+ const uint8_t* payload = ws_get_payload(parser);
+ size_t payload_len = ws_get_payload_length(parser);
+
+ if (payload && payload_len > 0) {
+ printf("\nPayload data:\n");
+ printf(" Length: %zu bytes\n", payload_len);
+ printf(" Hex: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ printf("%02X ", payload[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+
+ printf(" ASCII: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ if (payload[i] >= 32 && payload[i] <= 126) {
+ printf("%c", payload[i]);
+ } else {
+ printf(".");
+ }
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+ }
+
+ printf("\nParser state: %d\n", ws_parser_get_state(parser));
+
+ } else if (result == 0) {
+ printf("Incomplete frame, need more data\n");
+ printf("Parser state: %d\n", ws_parser_get_state(parser));
+ } else {
+ printf("Parse error\n");
+ printf("Parser state: %d\n", ws_parser_get_state(parser));
+ }
+
+ // 清理
+ ws_parser_destroy(parser);
}
-// 新增:获取当前解析状态
-ws_parse_state_t ws_parser_get_state(ws_parser_t* parser) {
- if (!parser) return WS_STATE_ERROR;
- return parser->state;
+int main() {
+ printf("WebSocket Parser Standalone Test\n");
+ printf("================================\n");
+
+ // 测试单帧解析
+ test_single_frame();
+
+ // 测试多帧解析
+ test_multiple_frames();
+
+ printf("\nAll tests completed.\n");
+ return 0;
}
-#ifdef __cplusplus
-}
-#endif
+#endif
\ No newline at end of file
continue;
} else if (errno == EINPROGRESS) {
/* 连接正在进行中,等待连接完成 */
- printf("tcp_send_and_wait_response: 连接正在进行中,等待连接完成...\n");
+ // printf("tcp_send_and_wait_response: 连接正在进行中,等待连接完成...\n");
if ((sys_now() - start_time) > timeout_ms) {
printf("tcp_send_and_wait_response: 等待连接完成超时\n");
return -1;
--- /dev/null
+CC = gcc
+CFLAGS = -Wall -Wextra -std=c99 -O2
+TARGET = websocket_test
+SOURCE = websocket_parser_standalone.cpp
+
+# 默认目标
+all: $(TARGET)
+
+# 编译目标
+$(TARGET): $(SOURCE)
+ $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE)
+
+# 清理
+clean:
+ rm -f $(TARGET)
+
+# 运行测试
+test: $(TARGET)
+ ./$(TARGET)
+
+# 显示帮助
+help:
+ @echo "Available targets:"
+ @echo " all - Build the test program"
+ @echo " clean - Remove build artifacts"
+ @echo " test - Build and run the test"
+ @echo " help - Show this help message"
+
+.PHONY: all clean test help
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+WebSocket数据解析工具
+分析十六进制数据,识别WebSocket帧结构,生成JSON报告
+"""
+
+import json
+import re
+from typing import List, Dict, Any
+
+class WebSocketFrameAnalyzer:
+ def __init__(self):
+ self.frames = []
+
+ def hex_to_bytes(self, hex_string: str) -> bytes:
+ """将十六进制字符串转换为字节"""
+ # 移除空格和换行符
+ hex_string = re.sub(r'\s+', '', hex_string)
+ return bytes.fromhex(hex_string)
+
+ def analyze_websocket_frame(self, data: bytes, offset: int) -> Dict[str, Any]:
+ """分析单个WebSocket帧"""
+ if len(data) < 2:
+ return None
+
+ # 解析第一个字节
+ first_byte = data[0]
+ fin = (first_byte >> 7) & 0x1
+ rsv = (first_byte >> 4) & 0x7
+ opcode = first_byte & 0x0F
+
+ # 解析第二个字节
+ second_byte = data[1]
+ mask = (second_byte >> 7) & 0x1
+ payload_len = second_byte & 0x7F
+
+ # 计算帧头大小
+ header_size = 2
+
+ # 扩展长度字段
+ if payload_len == 126:
+ if len(data) >= 4:
+ extended_len = int.from_bytes(data[2:4], 'big')
+ header_size += 2
+ else:
+ extended_len = 0
+ elif payload_len == 127:
+ if len(data) >= 10:
+ extended_len = int.from_bytes(data[2:10], 'big')
+ header_size += 8
+ else:
+ extended_len = 0
+ else:
+ extended_len = payload_len
+
+ # 掩码密钥
+ if mask:
+ header_size += 4
+
+ # 计算总帧大小
+ total_frame_size = header_size + extended_len
+
+ # 检查数据是否完整
+ if len(data) < total_frame_size:
+ return None
+
+ # 提取负载数据
+ payload_data = data[header_size:header_size + extended_len]
+
+ # 如果有掩码,需要解掩码
+ if mask and len(data) >= header_size + 4:
+ mask_key = data[header_size - 4:header_size]
+ unmasked_payload = bytearray(extended_len)
+ for i in range(extended_len):
+ unmasked_payload[i] = payload_data[i] ^ mask_key[i % 4]
+ payload_data = bytes(unmasked_payload)
+
+ # 解析JSON内容(如果可能)
+ json_content = None
+ try:
+ if payload_data:
+ json_content = json.loads(payload_data.decode('utf-8'))
+ except:
+ pass
+
+ # 构建帧信息
+ frame_info = {
+ "frame_index": len(self.frames),
+ "offset_in_stream": offset,
+ "frame_header": {
+ "fin": fin,
+ "rsv": rsv,
+ "opcode": opcode,
+ "opcode_name": self.get_opcode_name(opcode),
+ "mask": mask,
+ "payload_length": extended_len
+ },
+ "frame_structure": {
+ "header_size": header_size,
+ "total_frame_size": total_frame_size,
+ "payload_size": extended_len
+ },
+ "raw_data": {
+ "hex": data[:total_frame_size].hex(' ').upper(),
+ "bytes": list(data[:total_frame_size])
+ },
+ "payload": {
+ "hex": payload_data.hex(' ').upper() if payload_data else "",
+ "bytes": list(payload_data) if payload_data else [],
+ "utf8": payload_data.decode('utf-8', errors='ignore') if payload_data else "",
+ "json": json_content
+ }
+ }
+
+ return frame_info, total_frame_size
+
+ def get_opcode_name(self, opcode: int) -> str:
+ """获取操作码名称"""
+ opcode_names = {
+ 0x0: "CONTINUATION",
+ 0x1: "TEXT",
+ 0x2: "BINARY",
+ 0x8: "CLOSE",
+ 0x9: "PING",
+ 0xA: "PONG"
+ }
+ return opcode_names.get(opcode, f"UNKNOWN(0x{opcode:02X})")
+
+ def analyze_stream(self, hex_data: str) -> List[Dict[str, Any]]:
+ """分析整个数据流"""
+ data = self.hex_to_bytes(hex_data)
+ offset = 0
+
+ print(f"分析数据流,总长度: {len(data)} 字节")
+
+ while offset < len(data):
+ remaining_data = data[offset:]
+
+ # 尝试解析一个帧
+ result = self.analyze_websocket_frame(remaining_data, offset)
+
+ if result is None:
+ # 无法解析,跳过1字节
+ offset += 1
+ continue
+
+ frame_info, frame_size = result
+
+ # 添加到帧列表
+ self.frames.append(frame_info)
+
+ print(f"发现帧 {len(self.frames)}: {frame_info['frame_header']['opcode_name']} "
+ f"(FIN={frame_info['frame_header']['fin']}, "
+ f"长度={frame_info['frame_structure']['total_frame_size']} 字节)")
+
+ # 移动到下一个帧
+ offset += frame_size
+
+ print(f"总共发现 {len(self.frames)} 个WebSocket帧")
+ return self.frames
+
+ def save_to_json(self, filename: str):
+ """保存分析结果到JSON文件"""
+ output = {
+ "analysis_summary": {
+ "total_frames": len(self.frames),
+ "total_bytes": sum(frame["frame_structure"]["total_frame_size"] for frame in self.frames)
+ },
+ "frames": self.frames
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(output, f, ensure_ascii=False, indent=2)
+
+ print(f"分析结果已保存到: {filename}")
+
+def main():
+ # 原始十六进制数据
+ hex_data = """65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E
+ 74 65 6E 74 22 3A 22 EF BC 8C 22 2C 22 74 61 73
+ 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E
+ 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 B8 80 E5 AE 9A 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BE 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 84 89 E5 BF AB 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 9A 84 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BF 83 E6 83 85 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 90 A7 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F 98 98 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 43 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 20 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 8F AF E4 BB A5 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 92 8C 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 88 91 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 AF B4 E8 AF B4 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BB 80 E4 B9 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BA 8B 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 91 80 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F A7 90 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 41 7B 22 74 79 70 65 22 3A 22 65 6E 64 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 6E 75 6C 6C 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 81 7E 00 BB 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 39 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E4 BB 96 E4 BD A0 22 2C 22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22 3A 30 2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D 81 7E 00 C4 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C A8 E6 98 AF E6 AD A3 E5 B8 B8 22 2C 22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22 3A 30 2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D 81 7E 00 CD 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C A8 E6 98 AF E6 AD A3 E5 B8 B8 22 2C 22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22 3A 30 2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D"""
+
+ # 创建分析器
+ analyzer = WebSocketFrameAnalyzer()
+
+ # 分析数据流
+ frames = analyzer.analyze_stream(hex_data)
+
+ # 保存到JSON文件
+ analyzer.save_to_json("websocket_frames_analysis.json")
+
+ # 打印简要统计
+ print("\n=== 分析统计 ===")
+ print(f"总帧数: {len(frames)}")
+ print(f"总字节数: {sum(frame['frame_structure']['total_frame_size'] for frame in frames)}")
+
+ # 按操作码统计
+ opcode_stats = {}
+ for frame in frames:
+ opcode = frame['frame_header']['opcode_name']
+ opcode_stats[opcode] = opcode_stats.get(opcode, 0) + 1
+
+ print("\n操作码统计:")
+ for opcode, count in opcode_stats.items():
+ print(f" {opcode}: {count} 帧")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
--- /dev/null
+{
+ "analysis_summary": {
+ "total_frames": 33,
+ "total_bytes": 2361
+ },
+ "frames": [
+ {
+ "frame_index": 0,
+ "offset_in_stream": 0,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 5,
+ "opcode_name": "UNKNOWN(0x05)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 EF BC 8C 22 2C 22 74 61 73 6B 5F 69 64",
+ "bytes": [
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 239,
+ 188,
+ 140,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100
+ ]
+ },
+ "payload": {
+ "hex": "3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 EF BC 8C 22 2C 22 74 61 73 6B 5F 69 64",
+ "bytes": [
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 239,
+ 188,
+ 140,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100
+ ],
+ "utf8": ":\"middle\",\"content\":\",\",\"task_id",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 1,
+ "offset_in_stream": 36,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 58
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 60,
+ "payload_size": 58
+ },
+ "raw_data": {
+ "hex": "22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD",
+ "bytes": [
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 189
+ ]
+ },
+ "payload": {
+ "hex": "22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD",
+ "bytes": [
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 189
+ ],
+ "utf8": "\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 2,
+ "offset_in_stream": 96,
+ "frame_header": {
+ "fin": 1,
+ "rsv": 2,
+ "opcode": 0,
+ "opcode_name": "CONTINUATION",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "A0 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A",
+ "bytes": [
+ 160,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58
+ ]
+ },
+ "payload": {
+ "hex": "2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A",
+ "bytes": [
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58
+ ],
+ "utf8": ",\"task_id\":\"\",\"reasoning_content\":",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 3,
+ "offset_in_stream": 132,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 B8 80",
+ "bytes": [
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 184,
+ 128
+ ]
+ },
+ "payload": {
+ "hex": "7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 B8 80",
+ "bytes": [
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 184,
+ 128
+ ],
+ "utf8": "}H{\"type\":\"middle\",\"content\":\"一",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 4,
+ "offset_in_stream": 168,
+ "frame_header": {
+ "fin": 1,
+ "rsv": 6,
+ "opcode": 5,
+ "opcode_name": "UNKNOWN(0x05)",
+ "mask": 1,
+ "payload_length": 46
+ },
+ "frame_structure": {
+ "header_size": 6,
+ "total_frame_size": 52,
+ "payload_size": 46
+ },
+ "raw_data": {
+ "hex": "E5 AE 9A 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22",
+ "bytes": [
+ 229,
+ 174,
+ 154,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "EE 43 5F 49 C5 4B 48 00 A0 00 0E 0E B8 50 49 43 E9 4D 42 4B F4 45 73 41 F5 4C 58 47 F4 56 0E 18 B8 00 51 A0 DF 59 0E 56 E3 52 49 00 A0 00",
+ "bytes": [
+ 238,
+ 67,
+ 95,
+ 73,
+ 197,
+ 75,
+ 72,
+ 0,
+ 160,
+ 0,
+ 14,
+ 14,
+ 184,
+ 80,
+ 73,
+ 67,
+ 233,
+ 77,
+ 66,
+ 75,
+ 244,
+ 69,
+ 115,
+ 65,
+ 245,
+ 76,
+ 88,
+ 71,
+ 244,
+ 86,
+ 14,
+ 24,
+ 184,
+ 0,
+ 81,
+ 160,
+ 223,
+ 89,
+ 14,
+ 86,
+ 227,
+ 82,
+ 73,
+ 0,
+ 160,
+ 0
+ ],
+ "utf8": "C_IKH\u0000\u0000\u000e\u000ePICMBKEsALXGV\u000e\u0018\u0000QY\u000eVRI\u0000\u0000",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 5,
+ "offset_in_stream": 220,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 13,
+ "opcode_name": "UNKNOWN(0x0D)",
+ "mask": 0,
+ "payload_length": 105
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 107,
+ "payload_size": 105
+ },
+ "raw_data": {
+ "hex": "6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BE 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22",
+ "bytes": [
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 156,
+ 137,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 190,
+ 136,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BE 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22",
+ "bytes": [
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 156,
+ 137,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 190,
+ 136,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34
+ ],
+ "utf8": "ddle\",\"content\":\"有\",\"task_id\":\"\",\"reasoning_content\":\"\"}H{\"type\":\"middle\",\"content\":\"很\",\"task_id\":\"\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 6,
+ "offset_in_stream": 327,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 12,
+ "opcode_name": "UNKNOWN(0x0C)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D",
+ "bytes": [
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109
+ ]
+ },
+ "payload": {
+ "hex": "72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D",
+ "bytes": [
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109
+ ],
+ "utf8": "reasoning_content\":\"\"}H{\"type\":\"m",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 7,
+ "offset_in_stream": 363,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 9,
+ "opcode_name": "PING",
+ "mask": 0,
+ "payload_length": 100
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 102,
+ "payload_size": 100
+ },
+ "raw_data": {
+ "hex": "69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 84 89 E5 BF AB 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 9A 84 22 2C 22 74 61 73 6B",
+ "bytes": [
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 132,
+ 137,
+ 229,
+ 191,
+ 171,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 154,
+ 132,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107
+ ]
+ },
+ "payload": {
+ "hex": "64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 84 89 E5 BF AB 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 9A 84 22 2C 22 74 61 73 6B",
+ "bytes": [
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 132,
+ 137,
+ 229,
+ 191,
+ 171,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 154,
+ 132,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107
+ ],
+ "utf8": "dle\",\"content\":\"愉快\",\"task_id\":\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"的\",\"task",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 8,
+ "offset_in_stream": 465,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 5,
+ "opcode": 15,
+ "opcode_name": "UNKNOWN(0x0F)",
+ "mask": 0,
+ "payload_length": 105
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 107,
+ "payload_size": 105
+ },
+ "raw_data": {
+ "hex": "5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BF 83 E6 83 85 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45",
+ "bytes": [
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 191,
+ 131,
+ 230,
+ 131,
+ 133,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69
+ ]
+ },
+ "payload": {
+ "hex": "64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 BF 83 E6 83 85 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45",
+ "bytes": [
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 191,
+ 131,
+ 230,
+ 131,
+ 133,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69
+ ],
+ "utf8": "d\":\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"心情\",\"task_id\":\"\",\"reasoning_content\":\"\"}E",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 9,
+ "offset_in_stream": 572,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 7,
+ "opcode": 11,
+ "opcode_name": "UNKNOWN(0x0B)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 90 A7 22 2C 22 74 61",
+ "bytes": [
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 144,
+ 167,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97
+ ]
+ },
+ "payload": {
+ "hex": "74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 90 A7 22 2C 22 74 61",
+ "bytes": [
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 144,
+ 167,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97
+ ],
+ "utf8": "type\":\"middle\",\"content\":\"吧\",\"ta",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 10,
+ "offset_in_stream": 608,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 7,
+ "opcode": 3,
+ "opcode_name": "UNKNOWN(0x03)",
+ "mask": 0,
+ "payload_length": 107
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 109,
+ "payload_size": 107
+ },
+ "raw_data": {
+ "hex": "73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65",
+ "bytes": [
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 70,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101
+ ]
+ },
+ "payload": {
+ "hex": "5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65",
+ "bytes": [
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 70,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101
+ ],
+ "utf8": "_id\":\"\",\"reasoning_content\":\"\"}B{\"type\":\"middle\",\"content\":\"\",\"task_id\":\"\",\"reasoning_content\":\"\"}F{\"type",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 11,
+ "offset_in_stream": 717,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 58
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 60,
+ "payload_size": 58
+ },
+ "raw_data": {
+ "hex": "22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F 98 98 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22",
+ "bytes": [
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 240,
+ 159,
+ 152,
+ 152,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F 98 98 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22",
+ "bytes": [
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 240,
+ 159,
+ 152,
+ 152,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34
+ ],
+ "utf8": "\"middle\",\"content\":\"😘\",\"task_id\":\"\",\"reasoning_content\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 12,
+ "offset_in_stream": 777,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 3,
+ "opcode": 10,
+ "opcode_name": "PONG",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "3A 22 22 7D 82 43 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 20 22",
+ "bytes": [
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 67,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 32,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "22 7D 82 43 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 20 22",
+ "bytes": [
+ 34,
+ 125,
+ 130,
+ 67,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 32,
+ 34
+ ],
+ "utf8": "\"}C{\"type\":\"middle\",\"content\":\" \"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 13,
+ "offset_in_stream": 813,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 12,
+ "opcode_name": "UNKNOWN(0x0C)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22",
+ "bytes": [
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22",
+ "bytes": [
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34
+ ],
+ "utf8": "task_id\":\"\",\"reasoning_content\":\"\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 14,
+ "offset_in_stream": 849,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 7,
+ "opcode": 13,
+ "opcode_name": "UNKNOWN(0x0D)",
+ "mask": 1,
+ "payload_length": 2
+ },
+ "frame_structure": {
+ "header_size": 6,
+ "total_frame_size": 8,
+ "payload_size": 2
+ },
+ "raw_data": {
+ "hex": "7D 82 45 7B 22 74 79 70",
+ "bytes": [
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112
+ ]
+ },
+ "payload": {
+ "hex": "3C 0B",
+ "bytes": [
+ 60,
+ 11
+ ],
+ "utf8": "<\u000b",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 15,
+ "offset_in_stream": 857,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 5,
+ "opcode_name": "UNKNOWN(0x05)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64",
+ "bytes": [
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 189,
+ 160,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100
+ ]
+ },
+ "payload": {
+ "hex": "3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64",
+ "bytes": [
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 189,
+ 160,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100
+ ],
+ "utf8": ":\"middle\",\"content\":\"你\",\"task_id",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 16,
+ "offset_in_stream": 893,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 58
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 60,
+ "payload_size": 58
+ },
+ "raw_data": {
+ "hex": "22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 8F",
+ "bytes": [
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 143
+ ]
+ },
+ "payload": {
+ "hex": "22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 8F",
+ "bytes": [
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 143
+ ],
+ "utf8": "\"\",\"reasoning_content\":\"\"}H{\"type\":\"middle\",\"content\":\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 17,
+ "offset_in_stream": 953,
+ "frame_header": {
+ "fin": 1,
+ "rsv": 2,
+ "opcode": 15,
+ "opcode_name": "UNKNOWN(0x0F)",
+ "mask": 1,
+ "payload_length": 100
+ },
+ "frame_structure": {
+ "header_size": 6,
+ "total_frame_size": 106,
+ "payload_size": 100
+ },
+ "raw_data": {
+ "hex": "AF E4 BB A5 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 92 8C 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65",
+ "bytes": [
+ 175,
+ 228,
+ 187,
+ 165,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 146,
+ 140,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101
+ ]
+ },
+ "payload": {
+ "hex": "99 D1 43 5F D0 FA 4B 48 99 9F 00 0E 97 87 50 49 DA D6 4D 42 D2 CB 45 73 D8 CA 4C 58 DE CB 56 0E 81 87 00 51 39 E0 59 0E CF DC 52 49 99 9F 00 41 D2 C1 46 40 DE 87 0E 0E D8 CA 4C 58 DE CB 56 0E 81 87 C7 BE 37 87 0E 0E CF C4 51 47 E4 CC 46 0E 81 87 00 00 99 D7 47 4D C8 CA 4C 45 D5 C2 7D 4F D4 CB 56 49",
+ "bytes": [
+ 153,
+ 209,
+ 67,
+ 95,
+ 208,
+ 250,
+ 75,
+ 72,
+ 153,
+ 159,
+ 0,
+ 14,
+ 151,
+ 135,
+ 80,
+ 73,
+ 218,
+ 214,
+ 77,
+ 66,
+ 210,
+ 203,
+ 69,
+ 115,
+ 216,
+ 202,
+ 76,
+ 88,
+ 222,
+ 203,
+ 86,
+ 14,
+ 129,
+ 135,
+ 0,
+ 81,
+ 57,
+ 224,
+ 89,
+ 14,
+ 207,
+ 220,
+ 82,
+ 73,
+ 153,
+ 159,
+ 0,
+ 65,
+ 210,
+ 193,
+ 70,
+ 64,
+ 222,
+ 135,
+ 14,
+ 14,
+ 216,
+ 202,
+ 76,
+ 88,
+ 222,
+ 203,
+ 86,
+ 14,
+ 129,
+ 135,
+ 199,
+ 190,
+ 55,
+ 135,
+ 14,
+ 14,
+ 207,
+ 196,
+ 81,
+ 71,
+ 228,
+ 204,
+ 70,
+ 14,
+ 129,
+ 135,
+ 0,
+ 0,
+ 153,
+ 215,
+ 71,
+ 77,
+ 200,
+ 202,
+ 76,
+ 69,
+ 213,
+ 194,
+ 125,
+ 79,
+ 212,
+ 203,
+ 86,
+ 73
+ ],
+ "utf8": "C_KH\u0000\u000ePIMBEsLXV\u000e\u0000Q9Y\u000eRI\u0000AF@އ\u000e\u000eLXV\u000eǾ7\u000e\u000eQGF\u000e\u0000\u0000GMLE}OVI",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 18,
+ "offset_in_stream": 1059,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 14,
+ "opcode_name": "UNKNOWN(0x0E)",
+ "mask": 0,
+ "payload_length": 116
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 118,
+ "payload_size": 116
+ },
+ "raw_data": {
+ "hex": "6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 88 91 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 AF B4 E8 AF B4 22 2C 22 74",
+ "bytes": [
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 136,
+ 145,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 232,
+ 175,
+ 180,
+ 232,
+ 175,
+ 180,
+ 34,
+ 44,
+ 34,
+ 116
+ ]
+ },
+ "payload": {
+ "hex": "22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 88 91 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 AF B4 E8 AF B4 22 2C 22 74",
+ "bytes": [
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 136,
+ 145,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 232,
+ 175,
+ 180,
+ 232,
+ 175,
+ 180,
+ 34,
+ 44,
+ 34,
+ 116
+ ],
+ "utf8": "\":\"\"}E{\"type\":\"middle\",\"content\":\"我\",\"task_id\":\"\",\"reasoning_content\":\"\"}H{\"type\":\"middle\",\"content\":\"说说\",\"t",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 19,
+ "offset_in_stream": 1177,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 1,
+ "opcode_name": "TEXT",
+ "mask": 0,
+ "payload_length": 115
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 117,
+ "payload_size": 115
+ },
+ "raw_data": {
+ "hex": "61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D",
+ "bytes": [
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 156,
+ 137,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109
+ ]
+ },
+ "payload": {
+ "hex": "6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 9C 89 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 48 7B 22 74 79 70 65 22 3A 22 6D",
+ "bytes": [
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 230,
+ 156,
+ 137,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 72,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109
+ ],
+ "utf8": "k_id\":\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"有\",\"task_id\":\"\",\"reasoning_content\":\"\"}H{\"type\":\"m",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 20,
+ "offset_in_stream": 1294,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 9,
+ "opcode_name": "PING",
+ "mask": 0,
+ "payload_length": 100
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 102,
+ "payload_size": 100
+ },
+ "raw_data": {
+ "hex": "69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BB 80 E4 B9 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BA 8B 22 2C 22 74 61 73 6B",
+ "bytes": [
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 187,
+ 128,
+ 228,
+ 185,
+ 136,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 186,
+ 139,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107
+ ]
+ },
+ "payload": {
+ "hex": "64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BB 80 E4 B9 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BA 8B 22 2C 22 74 61 73 6B",
+ "bytes": [
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 187,
+ 128,
+ 228,
+ 185,
+ 136,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 186,
+ 139,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107
+ ],
+ "utf8": "dle\",\"content\":\"什么\",\"task_id\":\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"事\",\"task",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 21,
+ "offset_in_stream": 1396,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 5,
+ "opcode": 15,
+ "opcode_name": "UNKNOWN(0x0F)",
+ "mask": 0,
+ "payload_length": 105
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 107,
+ "payload_size": 105
+ },
+ "raw_data": {
+ "hex": "5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 91 80 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74",
+ "bytes": [
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 145,
+ 128,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116
+ ]
+ },
+ "payload": {
+ "hex": "64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 91 80 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74",
+ "bytes": [
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 69,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 229,
+ 145,
+ 128,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116
+ ],
+ "utf8": "d\":\"\",\"reasoning_content\":\"\"}E{\"type\":\"middle\",\"content\":\"呀\",\"task_id\":\"\",\"reasoning_content\":\"\"}B{\"t",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 22,
+ "offset_in_stream": 1503,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 7,
+ "opcode": 9,
+ "opcode_name": "PING",
+ "mask": 0,
+ "payload_length": 112
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 114,
+ "payload_size": 112
+ },
+ "raw_data": {
+ "hex": "79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F A7 90 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72",
+ "bytes": [
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 70,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 240,
+ 159,
+ 167,
+ 144,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114
+ ]
+ },
+ "payload": {
+ "hex": "65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 46 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 F0 9F A7 90 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72",
+ "bytes": [
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 70,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 240,
+ 159,
+ 167,
+ 144,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114
+ ],
+ "utf8": "e\":\"middle\",\"content\":\"\",\"task_id\":\"\",\"reasoning_content\":\"\"}F{\"type\":\"middle\",\"content\":\"🧐\",\"task_id\":\"\",\"r",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 23,
+ "offset_in_stream": 1617,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 5,
+ "opcode_name": "UNKNOWN(0x05)",
+ "mask": 0,
+ "payload_length": 97
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 99,
+ "payload_size": 97
+ },
+ "raw_data": {
+ "hex": "65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 41 7B 22 74 79 70 65 22 3A",
+ "bytes": [
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 65,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58
+ ]
+ },
+ "payload": {
+ "hex": "73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 42 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 82 41 7B 22 74 79 70 65 22 3A",
+ "bytes": [
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 66,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58,
+ 34,
+ 109,
+ 105,
+ 100,
+ 100,
+ 108,
+ 101,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 130,
+ 65,
+ 123,
+ 34,
+ 116,
+ 121,
+ 112,
+ 101,
+ 34,
+ 58
+ ],
+ "utf8": "soning_content\":\"\"}B{\"type\":\"middle\",\"content\":\"\",\"task_id\":\"\",\"reasoning_content\":\"\"}A{\"type\":",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 24,
+ "offset_in_stream": 1716,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 101
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 103,
+ "payload_size": 101
+ },
+ "raw_data": {
+ "hex": "22 65 6E 64 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 6E 75 6C 6C 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 81 7E 00 BB 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 74 61 73 6B 5F 69",
+ "bytes": [
+ 34,
+ 101,
+ 110,
+ 100,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 110,
+ 117,
+ 108,
+ 108,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 129,
+ 126,
+ 0,
+ 187,
+ 123,
+ 34,
+ 115,
+ 116,
+ 97,
+ 116,
+ 117,
+ 115,
+ 34,
+ 58,
+ 50,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 44,
+ 34,
+ 109,
+ 115,
+ 103,
+ 34,
+ 58,
+ 34,
+ 115,
+ 117,
+ 99,
+ 99,
+ 101,
+ 115,
+ 115,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105
+ ]
+ },
+ "payload": {
+ "hex": "6E 64 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 6E 75 6C 6C 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D 81 7E 00 BB 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 74 61 73 6B 5F 69",
+ "bytes": [
+ 110,
+ 100,
+ 34,
+ 44,
+ 34,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 110,
+ 117,
+ 108,
+ 108,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 97,
+ 115,
+ 111,
+ 110,
+ 105,
+ 110,
+ 103,
+ 95,
+ 99,
+ 111,
+ 110,
+ 116,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 34,
+ 125,
+ 129,
+ 126,
+ 0,
+ 187,
+ 123,
+ 34,
+ 115,
+ 116,
+ 97,
+ 116,
+ 117,
+ 115,
+ 34,
+ 58,
+ 50,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 44,
+ 34,
+ 109,
+ 115,
+ 103,
+ 34,
+ 58,
+ 34,
+ 115,
+ 117,
+ 99,
+ 99,
+ 101,
+ 115,
+ 115,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105
+ ],
+ "utf8": "nd\",\"content\":null,\"task_id\":\"\",\"reasoning_content\":\"\"}~\u0000{\"status\":20000000,\"msg\":\"success\",\"task_i",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 25,
+ "offset_in_stream": 1819,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 4,
+ "opcode_name": "UNKNOWN(0x04)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 39 34 33 33 37 62 64 65 33 37",
+ "bytes": [
+ 100,
+ 34,
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 57,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55
+ ]
+ },
+ "payload": {
+ "hex": "3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 39 34 33 33 37 62 64 65 33 37",
+ "bytes": [
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 57,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55
+ ],
+ "utf8": ":\"a1aee2d758a6d3933a246694337bde37",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 26,
+ "offset_in_stream": 1855,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 44
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 46,
+ "payload_size": 44
+ },
+ "raw_data": {
+ "hex": "22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E4 BB 96 E4 BD A0",
+ "bytes": [
+ 34,
+ 44,
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 187,
+ 150,
+ 228,
+ 189,
+ 160
+ ]
+ },
+ "payload": {
+ "hex": "22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E4 BB 96 E4 BD A0",
+ "bytes": [
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 228,
+ 187,
+ 150,
+ 228,
+ 189,
+ 160
+ ],
+ "utf8": "\"event\":\"Changed\",\"result\":{\"result\":\"他你",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 27,
+ "offset_in_stream": 1901,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 2,
+ "opcode": 2,
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 44
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 46,
+ "payload_size": 44
+ },
+ "raw_data": {
+ "hex": "22 2C 22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22",
+ "bytes": [
+ 34,
+ 44,
+ 34,
+ 105,
+ 115,
+ 95,
+ 101,
+ 110,
+ 100,
+ 34,
+ 58,
+ 102,
+ 97,
+ 108,
+ 115,
+ 101,
+ 44,
+ 34,
+ 115,
+ 101,
+ 110,
+ 116,
+ 101,
+ 110,
+ 99,
+ 101,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 115,
+ 116,
+ 97,
+ 114,
+ 116,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34
+ ]
+ },
+ "payload": {
+ "hex": "22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22",
+ "bytes": [
+ 34,
+ 105,
+ 115,
+ 95,
+ 101,
+ 110,
+ 100,
+ 34,
+ 58,
+ 102,
+ 97,
+ 108,
+ 115,
+ 101,
+ 44,
+ 34,
+ 115,
+ 101,
+ 110,
+ 116,
+ 101,
+ 110,
+ 99,
+ 101,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 115,
+ 116,
+ 97,
+ 114,
+ 116,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34
+ ],
+ "utf8": "\"is_end\":false,\"sentence_id\":\"\",\"start_time\"",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 28,
+ "offset_in_stream": 1947,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 3,
+ "opcode": 10,
+ "opcode_name": "PONG",
+ "mask": 0,
+ "payload_length": 48
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 50,
+ "payload_size": 48
+ },
+ "raw_data": {
+ "hex": "3A 30 2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D 81 7E 00 C4 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63",
+ "bytes": [
+ 58,
+ 48,
+ 44,
+ 34,
+ 101,
+ 110,
+ 100,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34,
+ 58,
+ 48,
+ 125,
+ 125,
+ 129,
+ 126,
+ 0,
+ 196,
+ 123,
+ 34,
+ 115,
+ 116,
+ 97,
+ 116,
+ 117,
+ 115,
+ 34,
+ 58,
+ 50,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 44,
+ 34,
+ 109,
+ 115,
+ 103,
+ 34,
+ 58,
+ 34,
+ 115,
+ 117,
+ 99
+ ]
+ },
+ "payload": {
+ "hex": "2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D 81 7E 00 C4 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63",
+ "bytes": [
+ 44,
+ 34,
+ 101,
+ 110,
+ 100,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34,
+ 58,
+ 48,
+ 125,
+ 125,
+ 129,
+ 126,
+ 0,
+ 196,
+ 123,
+ 34,
+ 115,
+ 116,
+ 97,
+ 116,
+ 117,
+ 115,
+ 34,
+ 58,
+ 50,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 44,
+ 34,
+ 109,
+ 115,
+ 103,
+ 34,
+ 58,
+ 34,
+ 115,
+ 117,
+ 99
+ ],
+ "utf8": ",\"end_time\":0}}~\u0000{\"status\":20000000,\"msg\":\"suc",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 29,
+ "offset_in_stream": 1997,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 3,
+ "opcode_name": "UNKNOWN(0x03)",
+ "mask": 0,
+ "payload_length": 101
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 103,
+ "payload_size": 101
+ },
+ "raw_data": {
+ "hex": "63 65 73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C",
+ "bytes": [
+ 99,
+ 101,
+ 115,
+ 115,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 105,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55,
+ 34,
+ 44,
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 156,
+ 139,
+ 232,
+ 181,
+ 183,
+ 230,
+ 157,
+ 165,
+ 231,
+ 142,
+ 176,
+ 229,
+ 156
+ ]
+ },
+ "payload": {
+ "hex": "73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C",
+ "bytes": [
+ 115,
+ 115,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 105,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55,
+ 34,
+ 44,
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 156,
+ 139,
+ 232,
+ 181,
+ 183,
+ 230,
+ 157,
+ 165,
+ 231,
+ 142,
+ 176,
+ 229,
+ 156
+ ],
+ "utf8": "ss\",\"task_id\":\"a1aee2d758a6d3933a2466i4337bde37\",\"event\":\"Changed\",\"result\":{\"result\":\"看起来现",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 30,
+ "offset_in_stream": 2100,
+ "frame_header": {
+ "fin": 1,
+ "rsv": 2,
+ "opcode": 8,
+ "opcode_name": "CLOSE",
+ "mask": 1,
+ "payload_length": 102
+ },
+ "frame_structure": {
+ "header_size": 6,
+ "total_frame_size": 108,
+ "payload_size": 102
+ },
+ "raw_data": {
+ "hex": "A8 E6 98 AF E6 AD A3 E5 B8 B8 22 2C 22 69 73 5F 65 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D 65 22 3A 30 2C 22 65 6E 64 5F 74 69 6D 65 22 3A 30 7D 7D 81 7E 00 CD 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 6D 73 67 22 3A 22 73 75 63 63 65",
+ "bytes": [
+ 168,
+ 230,
+ 152,
+ 175,
+ 230,
+ 173,
+ 163,
+ 229,
+ 184,
+ 184,
+ 34,
+ 44,
+ 34,
+ 105,
+ 115,
+ 95,
+ 101,
+ 110,
+ 100,
+ 34,
+ 58,
+ 102,
+ 97,
+ 108,
+ 115,
+ 101,
+ 44,
+ 34,
+ 115,
+ 101,
+ 110,
+ 116,
+ 101,
+ 110,
+ 99,
+ 101,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 115,
+ 116,
+ 97,
+ 114,
+ 116,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34,
+ 58,
+ 48,
+ 44,
+ 34,
+ 101,
+ 110,
+ 100,
+ 95,
+ 116,
+ 105,
+ 109,
+ 101,
+ 34,
+ 58,
+ 48,
+ 125,
+ 125,
+ 129,
+ 126,
+ 0,
+ 205,
+ 123,
+ 34,
+ 115,
+ 116,
+ 97,
+ 116,
+ 117,
+ 115,
+ 34,
+ 58,
+ 50,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 44,
+ 34,
+ 109,
+ 115,
+ 103,
+ 34,
+ 58,
+ 34,
+ 115,
+ 117,
+ 99,
+ 99,
+ 101
+ ]
+ },
+ "payload": {
+ "hex": "3B 4A 5E 15 BA 83 C4 C4 EB F0 83 C3 FC 8D DC CB F9 C3 95 C8 B4 8D 95 C8 F6 DB 83 C3 FB CA B9 C4 FC 8D DC 8F BA 83 C4 DE EC CE 94 D9 C7 DB 8F C0 FD 8D DC 9D B4 8D 83 C3 FC F0 92 C4 F5 CA C4 97 A8 D2 9B 2C E6 AF 2B D6 BA DC 92 CC EC DA 95 8F A2 9D D6 9D A8 9F D6 9D A8 83 C4 C0 EB C8 C4 97 BA DC 93 CE FB CA",
+ "bytes": [
+ 59,
+ 74,
+ 94,
+ 21,
+ 186,
+ 131,
+ 196,
+ 196,
+ 235,
+ 240,
+ 131,
+ 195,
+ 252,
+ 141,
+ 220,
+ 203,
+ 249,
+ 195,
+ 149,
+ 200,
+ 180,
+ 141,
+ 149,
+ 200,
+ 246,
+ 219,
+ 131,
+ 195,
+ 251,
+ 202,
+ 185,
+ 196,
+ 252,
+ 141,
+ 220,
+ 143,
+ 186,
+ 131,
+ 196,
+ 222,
+ 236,
+ 206,
+ 148,
+ 217,
+ 199,
+ 219,
+ 143,
+ 192,
+ 253,
+ 141,
+ 220,
+ 157,
+ 180,
+ 141,
+ 131,
+ 195,
+ 252,
+ 240,
+ 146,
+ 196,
+ 245,
+ 202,
+ 196,
+ 151,
+ 168,
+ 210,
+ 155,
+ 44,
+ 230,
+ 175,
+ 43,
+ 214,
+ 186,
+ 220,
+ 146,
+ 204,
+ 236,
+ 218,
+ 149,
+ 143,
+ 162,
+ 157,
+ 214,
+ 157,
+ 168,
+ 159,
+ 214,
+ 157,
+ 168,
+ 131,
+ 196,
+ 192,
+ 235,
+ 200,
+ 196,
+ 151,
+ 186,
+ 220,
+ 147,
+ 206,
+ 251,
+ 202
+ ],
+ "utf8": ";J^\u0015ÕȴۃʹΔۏܝėқ,+ֺܒڕ֝֝ėܓ",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 31,
+ "offset_in_stream": 2208,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 7,
+ "opcode": 3,
+ "opcode_name": "UNKNOWN(0x03)",
+ "mask": 0,
+ "payload_length": 115
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 117,
+ "payload_size": 115
+ },
+ "raw_data": {
+ "hex": "73 73 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C A8 E6 98 AF E6 AD A3 E5 B8 B8 22 2C 22 69 73 5F",
+ "bytes": [
+ 115,
+ 115,
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 105,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55,
+ 34,
+ 44,
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 156,
+ 139,
+ 232,
+ 181,
+ 183,
+ 230,
+ 157,
+ 165,
+ 231,
+ 142,
+ 176,
+ 229,
+ 156,
+ 168,
+ 230,
+ 152,
+ 175,
+ 230,
+ 173,
+ 163,
+ 229,
+ 184,
+ 184,
+ 34,
+ 44,
+ 34,
+ 105,
+ 115,
+ 95
+ ]
+ },
+ "payload": {
+ "hex": "22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 61 31 61 65 65 32 64 37 35 38 61 36 64 33 39 33 33 61 32 34 36 36 69 34 33 33 37 62 64 65 33 37 22 2C 22 65 76 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74 22 3A 22 E7 9C 8B E8 B5 B7 E6 9D A5 E7 8E B0 E5 9C A8 E6 98 AF E6 AD A3 E5 B8 B8 22 2C 22 69 73 5F",
+ "bytes": [
+ 34,
+ 44,
+ 34,
+ 116,
+ 97,
+ 115,
+ 107,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 97,
+ 49,
+ 97,
+ 101,
+ 101,
+ 50,
+ 100,
+ 55,
+ 53,
+ 56,
+ 97,
+ 54,
+ 100,
+ 51,
+ 57,
+ 51,
+ 51,
+ 97,
+ 50,
+ 52,
+ 54,
+ 54,
+ 105,
+ 52,
+ 51,
+ 51,
+ 55,
+ 98,
+ 100,
+ 101,
+ 51,
+ 55,
+ 34,
+ 44,
+ 34,
+ 101,
+ 118,
+ 101,
+ 110,
+ 116,
+ 34,
+ 58,
+ 34,
+ 67,
+ 104,
+ 97,
+ 110,
+ 103,
+ 101,
+ 100,
+ 34,
+ 44,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 123,
+ 34,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 34,
+ 58,
+ 34,
+ 231,
+ 156,
+ 139,
+ 232,
+ 181,
+ 183,
+ 230,
+ 157,
+ 165,
+ 231,
+ 142,
+ 176,
+ 229,
+ 156,
+ 168,
+ 230,
+ 152,
+ 175,
+ 230,
+ 173,
+ 163,
+ 229,
+ 184,
+ 184,
+ 34,
+ 44,
+ 34,
+ 105,
+ 115,
+ 95
+ ],
+ "utf8": "\",\"task_id\":\"a1aee2d758a6d3933a2466i4337bde37\",\"event\":\"Changed\",\"result\":{\"result\":\"看起来现在是正常\",\"is_",
+ "json": null
+ }
+ },
+ {
+ "frame_index": 32,
+ "offset_in_stream": 2327,
+ "frame_header": {
+ "fin": 0,
+ "rsv": 6,
+ "opcode": 4,
+ "opcode_name": "UNKNOWN(0x04)",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_structure": {
+ "header_size": 2,
+ "total_frame_size": 36,
+ "payload_size": 34
+ },
+ "raw_data": {
+ "hex": "64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D",
+ "bytes": [
+ 100,
+ 34,
+ 58,
+ 102,
+ 97,
+ 108,
+ 115,
+ 101,
+ 44,
+ 34,
+ 115,
+ 101,
+ 110,
+ 116,
+ 101,
+ 110,
+ 99,
+ 101,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 115,
+ 116,
+ 97,
+ 114,
+ 116,
+ 95,
+ 116,
+ 105,
+ 109
+ ]
+ },
+ "payload": {
+ "hex": "3A 66 61 6C 73 65 2C 22 73 65 6E 74 65 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72 74 5F 74 69 6D",
+ "bytes": [
+ 58,
+ 102,
+ 97,
+ 108,
+ 115,
+ 101,
+ 44,
+ 34,
+ 115,
+ 101,
+ 110,
+ 116,
+ 101,
+ 110,
+ 99,
+ 101,
+ 95,
+ 105,
+ 100,
+ 34,
+ 58,
+ 34,
+ 34,
+ 44,
+ 34,
+ 115,
+ 116,
+ 97,
+ 114,
+ 116,
+ 95,
+ 116,
+ 105,
+ 109
+ ],
+ "utf8": ":false,\"sentence_id\":\"\",\"start_tim",
+ "json": null
+ }
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+// 控制日志输出的宏
+#define ENABLE_DEBUG_LOG 1 // 设置为0可以关闭所有调试输出
+
+#if ENABLE_DEBUG_LOG
+#define WS_LOG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
+#define WS_LOGI(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOGD(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOGE(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__)
+#else
+#define WS_LOG(fmt, ...)
+#define WS_LOGI(fmt, ...)
+#define WS_LOGD(fmt, ...)
+#define WS_LOGE(fmt, ...)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * WebSocket协议解析器 (RFC 6455)
+ */
+
+// WebSocket帧类型枚举
+typedef enum {
+ WS_CONTINUATION = 0x0,
+ WS_TEXT = 0x1,
+ WS_BINARY = 0x2,
+ WS_CLOSE = 0x8,
+ WS_PING = 0x9,
+ WS_PONG = 0xA
+} ws_opcode_t;
+
+// WebSocket解析状态
+typedef enum {
+ WS_STATE_START,
+ WS_STATE_READ_HEADER1,
+ WS_STATE_READ_HEADER2,
+ WS_STATE_READ_PAYLOAD_LEN,
+ WS_STATE_READ_MASK,
+ WS_STATE_READ_PAYLOAD,
+ WS_STATE_COMPLETE,
+ WS_STATE_ERROR
+} ws_parse_state_t;
+
+// WebSocket帧头部信息
+typedef struct {
+ uint8_t fin; // 帧结束标志
+ uint8_t rsv1; // 保留位1
+ uint8_t rsv2; // 保留位2
+ uint8_t rsv3; // 保留位3
+ ws_opcode_t opcode; // 操作码
+ uint8_t mask; // 掩码标志
+ uint64_t payload_len; // 负载长度
+ uint8_t mask_key[4]; // 掩码密钥
+} ws_header_t;
+
+// WebSocket解析上下文
+typedef struct {
+ ws_parse_state_t state; // 当前解析状态
+ ws_header_t header; // 解析出的头部信息
+ uint8_t* buffer; // 数据缓存
+ size_t buffer_pos; // 缓存当前位置
+ size_t payload_remaining; // 剩余需要读取的负载长度
+ size_t mask_pos; // 掩码读取位置
+} ws_parser_t;
+
+// 全局动态分配缓存(1024字节)
+uint8_t* g_ws_buffer = NULL;
+#define WS_BUFFER_SIZE 1024
+
+// WebSocket协议长度限制配置
+#define WS_MAX_PAYLOAD_LEN_DEFAULT 65535 // 默认最大负载长度(16位)
+#define WS_MAX_PAYLOAD_LEN_MAX 1048576 // 最大允许的负载长度(1MB)
+#define WS_CONTROL_FRAME_MAX_LEN 125 // 控制帧最大负载长度(RFC 6455规定)
+
+static int g_parser_count = 0; // 解析器实例计数
+static uint64_t g_max_payload_len = WS_MAX_PAYLOAD_LEN_DEFAULT; // 全局最大负载长度配置
+
+// 初始化WebSocket解析器
+ws_parser_t* ws_parser_init() {
+ WS_LOGI("WS: Initializing WebSocket parser");
+
+ ws_parser_t* parser = (ws_parser_t*)malloc(sizeof(ws_parser_t));
+ if (!parser) {
+ WS_LOGE("WS: Failed to allocate memory for parser");
+ return NULL;
+ }
+
+ // 初始化全局缓存
+ if (!g_ws_buffer) {
+ WS_LOGI("WS: Allocating global buffer (%d bytes)", WS_BUFFER_SIZE);
+ g_ws_buffer = (uint8_t*)malloc(WS_BUFFER_SIZE);
+ if (!g_ws_buffer) {
+ WS_LOGE("WS: Failed to allocate global buffer");
+ free(parser);
+ return NULL;
+ }
+ }
+
+ g_parser_count++;
+ WS_LOGI("WS: Parser count: %d", g_parser_count);
+
+ // 初始化解析器状态
+ parser->state = WS_STATE_START;
+ parser->buffer = g_ws_buffer;
+ parser->buffer_pos = 0;
+ parser->payload_remaining = 0;
+ parser->mask_pos = 0;
+ memset(&parser->header, 0, sizeof(ws_header_t));
+
+ WS_LOGI("WS: Parser initialized successfully");
+ return parser;
+}
+
+// 重置解析器状态
+void ws_parser_reset(ws_parser_t* parser) {
+ if (!parser) return;
+
+ parser->state = WS_STATE_START;
+ parser->buffer_pos = 0;
+ parser->payload_remaining = 0;
+ parser->mask_pos = 0;
+ memset(&parser->header, 0, sizeof(ws_header_t));
+}
+
+// 应用掩码解码
+void apply_mask(uint8_t* data, size_t len, const uint8_t* mask_key, size_t offset) {
+ for (size_t i = 0; i < len; i++) {
+ data[i] ^= mask_key[(offset + i) % 4];
+ }
+}
+
+// 验证控制帧长度
+int validate_control_frame_length(ws_opcode_t opcode, uint64_t payload_len) {
+ if (opcode >= WS_CLOSE && opcode <= WS_PONG) {
+ if (payload_len > WS_CONTROL_FRAME_MAX_LEN) {
+ return 0; // 控制帧长度不能超过125字节
+ }
+ }
+ return 1;
+}
+
+// 配置最大负载长度
+int ws_set_max_payload_length(uint64_t max_len) {
+ WS_LOGI("WS: Setting max payload length to %llu bytes", (unsigned long long)max_len);
+
+ if (max_len > WS_MAX_PAYLOAD_LEN_MAX) {
+ WS_LOGE("WS: Max payload length %llu exceeds limit %llu",
+ (unsigned long long)max_len, (unsigned long long)WS_MAX_PAYLOAD_LEN_MAX);
+ return 0; // 超过最大允许值
+ }
+ if (max_len < 1) {
+ WS_LOGE("WS: Invalid max payload length: %llu (must be >= 1)", (unsigned long long)max_len);
+ return 0; // 不能小于1字节
+ }
+ g_max_payload_len = max_len;
+ WS_LOGI("WS: Max payload length set successfully");
+ return 1;
+}
+
+// 获取当前配置的最大负载长度
+uint64_t ws_get_max_payload_length(void) {
+ return g_max_payload_len;
+}
+
+// 解析单个字节
+// 返回值:0-继续解析,1-解析完成一个帧,-1-错误
+int ws_parse_byte(ws_parser_t* parser, uint8_t byte) {
+ if (!parser || parser->state == WS_STATE_ERROR) {
+ return -1;
+ }
+
+ switch (parser->state) {
+ case WS_STATE_START:
+ parser->state = WS_STATE_READ_HEADER1;
+ // 继续执行,处理第一个字节
+
+ case WS_STATE_READ_HEADER1:{
+ // 解析第一个头部字节
+ parser->header.fin = (byte >> 7) & 0x1;
+ parser->header.rsv1 = (byte >> 6) & 0x1;
+ parser->header.rsv2 = (byte >> 5) & 0x1;
+ parser->header.rsv3 = (byte >> 4) & 0x1;
+ parser->header.opcode = (ws_opcode_t)(byte & 0x0F);
+
+ // 检查 opcode 是否有效
+ if (!((parser->header.opcode >= WS_CONTINUATION && parser->header.opcode <= WS_BINARY) ||
+ (parser->header.opcode >= WS_CLOSE && parser->header.opcode <= WS_PONG))) {
+ WS_LOGE("WS: Invalid opcode: 0x%02X", parser->header.opcode);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 检查RSV位是否都为0(根据RFC6455规范)
+ if (!(parser->header.fin == 1 && parser->header.rsv1 == 0 && parser->header.rsv2 == 0 && parser->header.rsv3 == 0))
+ {
+ WS_LOGE("WS: Invalid RSV bits: %d%d%d",
+ parser->header.rsv1, parser->header.rsv2, parser->header.rsv3);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ WS_LOGD("WS: Parse header1 - FIN:%d, RSV:%d%d%d, OPCODE:0x%02X",
+ parser->header.fin, parser->header.rsv1, parser->header.rsv2, parser->header.rsv3, parser->header.opcode);
+
+
+
+ // 保存第一个头部字节到缓存
+ if (parser->buffer_pos < WS_BUFFER_SIZE) {
+ parser->buffer[parser->buffer_pos++] = byte;
+ } else {
+ parser->state = WS_STATE_ERROR;
+ WS_LOGE("WS: Buffer overflow in header1");
+ return -1;
+ }
+
+ parser->state = WS_STATE_READ_HEADER2;
+ break;
+ }
+
+ case WS_STATE_READ_HEADER2: {
+ // 解析第二个头部字节
+ parser->header.mask = (byte >> 7) & 0x1;
+ uint8_t payload_len = byte & 0x7F;
+
+ WS_LOGD("WS: Parse header2 - MASK:%d, LEN:%d",
+ parser->header.mask, payload_len);
+
+ // 保存第二个头部字节到缓存
+ if (parser->buffer_pos < WS_BUFFER_SIZE) {
+ parser->buffer[parser->buffer_pos++] = byte;
+ } else {
+ parser->state = WS_STATE_ERROR;
+ WS_LOGE("WS: Buffer overflow in header2");
+ return -1;
+ }
+
+ // 处理负载长度
+ if (payload_len <= 125) {
+ parser->header.payload_len = payload_len;
+ parser->payload_remaining = payload_len;
+
+ WS_LOGI("WS: Small payload length: %d bytes", payload_len);
+
+ // 验证控制帧长度
+ if (!validate_control_frame_length(parser->header.opcode, payload_len)) {
+ WS_LOGE("WS: Control frame length validation failed: opcode=0x%02X, len=%d",
+ parser->header.opcode, payload_len);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 如果有掩码,下一步读取掩码
+ if (parser->header.mask) {
+ parser->state = WS_STATE_READ_MASK;
+ } else {
+ // 无掩码,直接读取负载
+ if (parser->payload_remaining == 0) {
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ parser->state = WS_STATE_READ_PAYLOAD;
+ }
+ } else if (payload_len == 126) {
+ // 16位长度,需要再读取2个字节
+ WS_LOGI("WS: Extended 16-bit payload length mode");
+ parser->header.payload_len = 126; // 临时标记
+ parser->payload_remaining = 2;
+ parser->state = WS_STATE_READ_PAYLOAD_LEN;
+ } else if (payload_len == 127) {
+ // 64位长度,需要再读取8个字节
+ WS_LOGI("WS: Extended 64-bit payload length mode");
+ parser->header.payload_len = 127; // 临时标记
+ parser->payload_remaining = 8;
+ parser->state = WS_STATE_READ_PAYLOAD_LEN;
+ }
+ break;
+ }
+
+ case WS_STATE_READ_PAYLOAD_LEN: {
+ // 保存长度字节到缓存
+ // if (parser->buffer_pos < WS_BUFFER_SIZE) {
+ // parser->buffer_pos++;
+ // } else {
+ // parser->state = WS_STATE_ERROR;
+ // WS_LOGE("WS: Buffer overflow in payload length");
+ // return -1;
+ // }
+
+ // 累加长度数据
+ static uint8_t len_bytes[8];
+
+ WS_LOGD("WS: Reading payload length byte: 0x%02X, remaining: %zu",
+ byte, parser->payload_remaining);
+
+ if (parser->header.payload_len == 126) {
+ // 16位扩展长度:只需要2个字节
+ if (parser->payload_remaining == 2) {
+ len_bytes[0] = byte; // 高字节
+ } else if (parser->payload_remaining == 1) {
+ len_bytes[1] = byte; // 低字节
+ }
+
+ parser->payload_remaining--;
+
+ if (parser->payload_remaining == 0) {
+ // 计算16位长度
+ parser->header.payload_len = (len_bytes[0] << 8) | len_bytes[1];
+ parser->payload_remaining = parser->header.payload_len;
+
+ WS_LOGI("WS: 16-bit payload length: %d bytes (0x%02X%02X)",
+ parser->header.payload_len, len_bytes[0], len_bytes[1]);
+
+ // 验证控制帧长度
+ if (!validate_control_frame_length(parser->header.opcode, parser->header.payload_len)) {
+ WS_LOGE("WS: Control frame length validation failed for 16-bit length");
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 检查负载长度是否合理
+ if (parser->header.payload_len > g_max_payload_len) {
+ WS_LOGE("WS: Payload length %d exceeds maximum %llu",
+ parser->header.payload_len, (unsigned long long)g_max_payload_len);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 检查缓存是否足够
+ if (parser->buffer_pos + parser->header.payload_len > WS_BUFFER_SIZE) {
+ WS_LOGE("WS: Buffer overflow: current=%zu, adding=%d, max=%d",
+ parser->buffer_pos, parser->header.payload_len, WS_BUFFER_SIZE);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 处理掩码
+ if (parser->header.mask) {
+ WS_LOGI("WS: Moving to READ_MASK state");
+ parser->state = WS_STATE_READ_MASK;
+ } else {
+ if (parser->payload_remaining == 0) {
+ WS_LOGI("WS: Zero payload, moving to COMPLETE state");
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ WS_LOGI("WS: Moving to READ_PAYLOAD state");
+ parser->state = WS_STATE_READ_PAYLOAD;
+ }
+ }
+ } else if (parser->header.payload_len == 127) {
+ // 64位扩展长度:需要8个字节
+ size_t byte_index = 8 - parser->payload_remaining;
+ len_bytes[byte_index] = byte;
+
+ parser->payload_remaining--;
+
+ if (parser->payload_remaining == 0) {
+ // 计算64位长度
+ parser->header.payload_len = 0;
+ for (int i = 0; i < 8; i++) {
+ parser->header.payload_len = (parser->header.payload_len << 8) | len_bytes[i];
+ }
+ parser->payload_remaining = parser->header.payload_len;
+
+ WS_LOGI("WS: 64-bit payload length: %llu bytes",
+ (unsigned long long)parser->header.payload_len);
+
+ // 验证控制帧长度
+ if (!validate_control_frame_length(parser->header.opcode, parser->header.payload_len)) {
+ WS_LOGE("WS: Control frame length validation failed for 64-bit length");
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 检查负载长度是否合理
+ if (parser->header.payload_len > g_max_payload_len) {
+ WS_LOGE("WS: Payload length %llu exceeds maximum %llu",
+ (unsigned long long)parser->header.payload_len, (unsigned long long)g_max_payload_len);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 检查缓存是否足够
+ if (parser->buffer_pos + parser->header.payload_len > WS_BUFFER_SIZE) {
+ WS_LOGE("WS: Buffer overflow: current=%zu, adding=%llu, max=%d",
+ parser->buffer_pos, (unsigned long long)parser->header.payload_len, WS_BUFFER_SIZE);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ // 处理掩码
+ if (parser->header.mask) {
+ WS_LOGI("WS: Moving to READ_MASK state");
+ parser->state = WS_STATE_READ_MASK;
+ return 1;
+ } else {
+ if (parser->payload_remaining == 0) {
+ WS_LOGI("WS: Zero payload, moving to COMPLETE state");
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ WS_LOGI("WS: Moving to READ_PAYLOAD state");
+ parser->state = WS_STATE_READ_PAYLOAD;
+ }
+ }
+ }
+ break;
+ }
+
+ case WS_STATE_READ_MASK: {
+ // 读取掩码密钥
+ if (parser->mask_pos < 4) {
+ parser->header.mask_key[parser->mask_pos++] = byte;
+
+ if (parser->mask_pos == 4) {
+ WS_LOGI("WS: Mask key read complete: 0x%02X%02X%02X%02X",
+ parser->header.mask_key[0], parser->header.mask_key[1],
+ parser->header.mask_key[2], parser->header.mask_key[3]);
+
+ if (parser->payload_remaining == 0) {
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ parser->state = WS_STATE_READ_PAYLOAD;
+ }
+ }
+ break;
+ }
+
+ case WS_STATE_READ_PAYLOAD: {
+ // 读取负载数据
+ if (parser->buffer_pos < WS_BUFFER_SIZE) {
+ parser->buffer[parser->buffer_pos++] = byte;
+ parser->payload_remaining--;
+
+ if (parser->payload_remaining == 0) {
+ // 负载读取完成
+ WS_LOGI("WS: Payload read complete (%zu bytes)", parser->header.payload_len);
+
+ // 如果有掩码,应用掩码解码
+ if (parser->header.mask) {
+ // 计算负载在缓存中的起始位置
+ size_t payload_start = parser->buffer_pos - parser->header.payload_len;
+ apply_mask(parser->buffer + payload_start, parser->header.payload_len,
+ parser->header.mask_key, 0);
+ WS_LOGI("WS: Mask applied to payload");
+ }
+
+ parser->state = WS_STATE_COMPLETE;
+ return 1;
+ }
+ } else {
+ parser->state = WS_STATE_ERROR;
+ WS_LOGE("WS: Buffer overflow in payload");
+ return -1;
+ }
+ break;
+ }
+
+ case WS_STATE_COMPLETE:
+ WS_LOGI("WS: Frame parsing complete, transitioning to COMPLETE state");
+ return 1;
+
+ case WS_STATE_ERROR:
+ WS_LOGE("WS: Parser is in error state");
+ return -1;
+
+ default:
+ WS_LOGE("WS: Unknown parser state: %d", parser->state);
+ parser->state = WS_STATE_ERROR;
+ return -1;
+ }
+
+ return 0; // 继续解析
+}
+
+// 解析数据流
+int ws_parse_stream(ws_parser_t* parser, const uint8_t* data, size_t len) {
+ if (!parser || !data || len == 0) {
+ WS_LOGE("WS: Invalid parameters for ws_parse_stream");
+ return -1;
+ }
+
+ WS_LOGI("WS: Parsing stream data (%zu bytes), current state: %d, buffer_pos: %zu",
+ len, parser->state, parser->buffer_pos);
+
+ // 如果解析器已经完成一个帧,重置状态
+ if (parser->state == WS_STATE_COMPLETE) {
+ WS_LOGI("WS: Parser was in COMPLETE state, resetting for new frame");
+ ws_parser_reset(parser);
+ }
+
+ int total_processed = 0;
+
+ for (size_t i = 0; i < len; i++) {
+ int result = ws_parse_byte(parser, data[i]);
+
+ if (result == 1) {
+ // 帧解析完成
+ WS_LOGI("WS: Complete frame parsed (%zu bytes total) opcode: %d, payload_len: %llu",
+ parser->buffer_pos, parser->header.opcode, (unsigned long long)parser->header.payload_len);
+ total_processed = i + 1;
+ break;
+ } else if (result == -1) {
+ // 解析错误
+ WS_LOGE("WS: Parsing error at byte %zu", i);
+ ws_parser_reset(parser);
+ // return -1;
+ total_processed = i + 1;
+ }
+ // result == 0 继续解析
+ }
+
+ if (parser->state == WS_STATE_COMPLETE) {
+ WS_LOGI(" WS_STATE_COMPLETE at %d\n",total_processed);
+ } else if (parser->state == WS_STATE_ERROR) {
+ WS_LOGI(" WS_STATE_ERROR at %d\n",total_processed);
+ } else {
+ // 数据不完整,继续等待更多数据
+ WS_LOGI("WS: Frame parsing incomplete, waiting for more data. State: %d, Buffer: %zu/%d, Payload remaining: %zu",
+ parser->state, parser->buffer_pos, WS_BUFFER_SIZE, parser->payload_remaining);
+ }
+ return total_processed;
+}
+
+// 获取解析出的头部信息
+const ws_header_t* ws_get_header(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
+ }
+ return &parser->header;
+}
+
+// 获取完整数据包(包含帧头)
+const uint8_t* ws_get_packet(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
+ }
+ return parser->buffer;
+}
+
+// 获取纯载荷数据
+const uint8_t* ws_get_payload(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return NULL;
+ }
+
+ // 计算载荷数据的起始位置
+ // 帧头:2字节(基本头部)
+ size_t header_size = 2;
+
+ // 扩展长度字段
+ if (parser->header.payload_len == 126) {
+ header_size += 2; // 16位长度
+ } else if (parser->header.payload_len == 127) {
+ header_size += 8; // 64位长度
+ }
+
+ // 掩码密钥
+ if (parser->header.mask) {
+ header_size += 4;
+ }
+
+ // 检查载荷数据是否在缓存范围内
+ if (header_size + parser->header.payload_len > parser->buffer_pos) {
+ WS_LOGE("WS: Payload start position %zu exceeds buffer size %zu", header_size, parser->buffer_pos);
+ return NULL;
+ }
+
+ return parser->buffer + header_size;
+}
+
+// 获取载荷数据长度
+size_t ws_get_payload_length(ws_parser_t* parser) {
+ if (!parser || parser->state != WS_STATE_COMPLETE) {
+ return 0;
+ }
+ return parser->header.payload_len;
+}
+
+// 检查解析器是否有错误
+int ws_parser_has_error(ws_parser_t* parser) {
+ return (parser && parser->state == WS_STATE_ERROR) ? 1 : 0;
+}
+
+// 获取解析器当前状态
+ws_parse_state_t ws_parser_get_state(ws_parser_t* parser) {
+ return parser ? parser->state : WS_STATE_ERROR;
+}
+
+// 销毁解析器
+void ws_parser_destroy(ws_parser_t* parser) {
+ if (parser) {
+ free(parser);
+ g_parser_count--;
+
+ // 如果所有解析器都被销毁,释放全局缓存
+ if (g_parser_count == 0 && g_ws_buffer) {
+ free(g_ws_buffer);
+ g_ws_buffer = NULL;
+ WS_LOGI("WS: Global buffer freed");
+ }
+
+ WS_LOGI("WS: Parser destroyed, remaining parsers: %d", g_parser_count);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+#if 1
+// 多包拆解测试函数
+void test_multiple_frames() {
+ printf("\n=== Multiple WebSocket Frames Test ===\n");
+
+ // 测试数据:包含多个WebSocket帧
+ uint8_t test_data[] = {
+ // 第一个帧:5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第二个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 E6 A0 B7 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ 0x99, 0xE6, 0xA0, 0xB7, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第三个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 9A 84 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 74, 0x22, 0x3A, 0x22, 0xE7, 0x9A,
+ 0x84, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第四个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 95 B0 E5 AD 97 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x95,
+ 0xB0, 0xE5, 0xAD, 0x97, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第五个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E7 BB 84 E5 90 88 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE7, 0xBB,
+ 0x84, 0xE5, 0x90, 0x88, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第六个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 91 A2 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x91,
+ 0xA2, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第七个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E3 80 82 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE3, 0x80,
+ 0x82, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第八个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E4 BD A0 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE4, 0xBD,
+ 0xA0, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第九个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 83 BD 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0x83,
+ 0xBD, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 AF B4 E8 AF B4 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xAF,
+ 0xB4, 0xE8, 0xAF, 0xB4, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十一个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ 0x99, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十二个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 87 A0 E4 B8 AA 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x87,
+ 0xA0, 0xE4, 0xB8, 0xAA, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十三个帧:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 95 B0 E5 AD 97 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x95,
+ 0xB0, 0xE5, 0xAD, 0x97, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十四个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E6 98 AF 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE6, 0x98,
+ 0xAF, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D,
+
+ // 第十五个帧:82 45 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E5 9C A8 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+ 0x82, 0x45, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE5, 0x9C,
+ 0xA8, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C,
+ 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D
+ };
+
+ size_t test_data_len = sizeof(test_data);
+
+ printf("Test data length: %zu bytes\n", test_data_len);
+ printf("Test data (hex): ");
+ for (size_t i = 0; i < test_data_len; i++) {
+ printf("%02X ", test_data[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ printf("\n");
+
+ // 创建解析器
+ ws_parser_t* parser = ws_parser_init();
+ if (!parser) {
+ printf("Failed to create parser\n");
+ return;
+ }
+
+ // 多包拆解测试
+ printf("\n=== Starting Multi-Frame Parsing ===\n");
+
+ size_t offset = 0;
+ int frame_count = 0;
+
+ while (offset < test_data_len) {
+ printf("\n--- Frame %d ---\n", frame_count + 1);
+ printf("Remaining data: %zu bytes\n", test_data_len - offset);
+
+ // 解析当前帧
+ int result = ws_parse_stream(parser, test_data + offset, test_data_len - offset);
+ ws_parse_state_t ws_state = ws_parser_get_state(parser);
+ printf("ws_state: %d,result: %d\n", ws_state,result);
+ if (result > 0 && ws_state == WS_STATE_COMPLETE) {
+ frame_count++;
+ printf("Frame %d parsed successfully, consumed %d bytes\n", frame_count, result);
+
+ const ws_header_t* header = ws_get_header(parser);
+ if (header) {
+ printf("Frame header:\n");
+ printf(" FIN: %d\n", header->fin);
+ printf(" RSV: %d%d%d\n", header->rsv1, header->rsv2, header->rsv3);
+ printf(" Opcode: 0x%02X\n", header->opcode);
+ printf(" Mask: %d\n", header->mask);
+ printf(" Payload length: %llu\n", (unsigned long long)header->payload_len);
+
+ if (header->mask) {
+ printf(" Mask key: 0x%02X%02X%02X%02X\n",
+ header->mask_key[0], header->mask_key[1],
+ header->mask_key[2], header->mask_key[3]);
+ }
+ }
+
+ const uint8_t* payload = ws_get_payload(parser);
+ size_t payload_len = ws_get_payload_length(parser);
+
+ if (payload && payload_len > 0) {
+ printf("Payload data:\n");
+ printf(" Length: %zu bytes\n", payload_len);
+ printf(" Hex: ");
+ for (size_t i = 0; i < payload_len && i < 32; i++) {
+ printf("%02X ", payload[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ if (payload_len > 32) printf("...");
+ printf("\n");
+
+ printf(" ASCII: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ if (payload[i] >= 32 && payload[i] <= 126) {
+ printf("%c", payload[i]);
+ } else {
+ printf(".");
+ }
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+ }
+
+
+
+ // 重置解析器状态,准备解析下一个帧
+ ws_parser_reset(parser);
+
+ } else if (result > 0 && ws_state != WS_STATE_ERROR) {
+ printf("Parser state: %d reset \n", ws_parser_get_state(parser));
+ // 重置解析器状态,准备解析下一个帧
+ ws_parser_reset(parser);
+ } else {
+ printf("Incomplete frame, need more data\n");
+ // printf("Parse error at offset %zu\n", offset);
+ // printf("Parser state: %d\n", ws_parser_get_state(parser));
+ }
+
+ // 移动到下一个帧
+ offset += result;
+ // 添加安全检查
+ if (offset >= test_data_len) {
+ printf("Reached end of data\n");
+ break;
+ }
+ }
+
+ printf("\n=== Multi-Frame Parsing Complete ===\n");
+ printf("Total frames parsed: %d\n", frame_count);
+ printf("Total bytes processed: %zu\n", offset);
+ printf("Remaining bytes: %zu\n", test_data_len - offset);
+
+ // 清理
+ ws_parser_destroy(parser);
+}
+
+// 单帧测试函数(保留原有功能)
+void test_single_frame() {
+ printf("\n=== Single WebSocket Frame Test ===\n");
+
+ // 测试数据:82 48 7B 22 74 79 70 65 22 3A 22 6D 69 64 64 6C 65 22 2C 22 63 6F 6E 74 65 6E 74 22 3A 22 E8 BF 99 E6 A0 B7 22 2C 22 74 61 73 6B 5F 69 64 22 3A 22 22 2C 22 72 65 61 73 6F 6E 69 6E 67 5F 63 6F 6E 74 65 6E 74 22 3A 22 22 7D
+
+ // 测试数据:WebSocket帧
+uint8_t test_data[] = {
+ // WebSocket帧头: 81 7E (FIN=1, Opcode=1, Mask=0, PayloadLen=126)
+ 0x81, 0x7E,
+
+ // 扩展长度: 00 BB (187字节)
+ 0x00, 0xBB,
+
+ // 负载数据开始: 7B 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30
+ 0x7B, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3A, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+
+ // 继续负载数据: 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22
+ 0x2C, 0x22, 0x6D, 0x73, 0x67, 0x22, 0x3A, 0x22, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+
+ // 继续负载数据: 2C 22 74 61 73 6B 5F 69 64 22 3A 22 34 63 64 39 35
+ 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x34, 0x63, 0x64, 0x39, 0x35,
+
+ // 继续负载数据: 62 62 39 35 63 37 35 39 32 65 38 38 31 31 63 37
+ 0x62, 0x62, 0x39, 0x35, 0x63, 0x37, 0x35, 0x39, 0x32, 0x65, 0x38, 0x38, 0x31, 0x31, 0x63, 0x37,
+
+ // 继续负载数据: 65 37 65 36 64 33 36 65 39 32 35 22 2C 22 65 76
+ 0x65, 0x37, 0x65, 0x36, 0x64, 0x33, 0x36, 0x65, 0x39, 0x32, 0x35, 0x22, 0x2C, 0x22, 0x65, 0x76,
+
+ // 继续负载数据: 65 6E 74 22 3A 22 43 68 61 6E 67 65 64 22 2C 22
+ 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x43, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x64, 0x22, 0x2C, 0x22,
+
+ // 继续负载数据: 72 65 73 75 6C 74 22 3A 7B 22 72 65 73 75 6C 74
+ 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x22, 0x3A, 0x7B, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74,
+
+ // 继续负载数据: 22 3A 22 E4 BD A0 EF BC 8C 22 2C 22 69 73 5F 65
+ 0x22, 0x3A, 0x22, 0xE4, 0xBD, 0xA0, 0xEF, 0xBC, 0x8C, 0x22, 0x2C, 0x22, 0x69, 0x73, 0x5F, 0x65,
+
+ // 继续负载数据: 6E 64 22 3A 66 61 6C 73 65 2C 22 73 65 6E 74 65
+ 0x6E, 0x64, 0x22, 0x3A, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x22, 0x2C, 0x22, 0x73, 0x65, 0x6E, 0x74,
+
+ // 继续负载数据: 6E 63 65 5F 69 64 22 3A 22 22 2C 22 73 74 61 72
+ 0x6E, 0x63, 0x65, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x22, 0x22, 0x2C, 0x22, 0x73, 0x74, 0x61, 0x72,
+
+ // 继续负载数据: 74 5F 74 69 6D 65 22 3A 30 2C 22 65 6E 64 5F 74
+ 0x74, 0x5F, 0x74, 0x69, 0x6D, 0x65, 0x22, 0x3A, 0x30, 0x22, 0x2C, 0x22, 0x65, 0x6E, 0x64, 0x5F, 0x74,
+
+ // 继续负载数据: 69 6D 65 22 3A 30 7D 7D
+ 0x69, 0x6D, 0x65, 0x22, 0x3A, 0x30, 0x7D, 0x7D
+};
+ // uint8_t test_data[] = {
+ // 0x82, 0x48, 0x7B, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C,
+ // 0x65, 0x22, 0x2C, 0x22, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0xE8, 0xBF,
+ // 0x99, 0xE6, 0xA0, 0xB7, 0x22, 0x2C, 0x22, 0x74, 0x61, 0x73, 0x6B, 0x5F, 0x69, 0x64, 0x22, 0x3A,
+ // 0x22, 0x22, 0x2C, 0x22, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x69, 0x6E, 0x67, 0x5F, 0x63, 0x6F,
+ // 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D
+ // };
+
+ size_t test_data_len = sizeof(test_data);
+
+ printf("Test data length: %zu bytes\n", test_data_len);
+ printf("Test data (hex): ");
+ for (size_t i = 0; i < test_data_len; i++) {
+ printf("%02X ", test_data[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ printf("\n");
+
+ // 创建解析器
+ ws_parser_t* parser = ws_parser_init();
+ if (!parser) {
+ printf("Failed to create parser\n");
+ return;
+ }
+
+ // 解析数据
+ int result = ws_parse_stream(parser, test_data, test_data_len);
+
+ if (result > 0) {
+ printf("\n=== Parse Result ===\n");
+ printf("Parsed bytes: %d\n", result);
+
+ const ws_header_t* header = ws_get_header(parser);
+ if (header) {
+ printf("Frame header:\n");
+ printf(" FIN: %d\n", header->fin);
+ printf(" RSV: %d%d%d\n", header->rsv1, header->rsv2, header->rsv3);
+ printf(" Opcode: 0x%02X\n", header->opcode);
+ printf(" Mask: %d\n", header->mask);
+ printf(" Payload length: %llu\n", (unsigned long long)header->payload_len);
+
+ if (header->mask) {
+ printf(" Mask key: 0x%02X%02X%02X%02X\n",
+ header->mask_key[0], header->mask_key[1],
+ header->mask_key[2], header->mask_key[3]);
+ }
+ }
+
+ const uint8_t* payload = ws_get_payload(parser);
+ size_t payload_len = ws_get_payload_length(parser);
+
+ if (payload && payload_len > 0) {
+ printf("\nPayload data:\n");
+ printf(" Length: %zu bytes\n", payload_len);
+ printf(" Hex: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ printf("%02X ", payload[i]);
+ if ((i + 1) % 16 == 0) printf("\n ");
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+
+ printf(" ASCII: ");
+ for (size_t i = 0; i < payload_len && i < 64; i++) {
+ if (payload[i] >= 32 && payload[i] <= 126) {
+ printf("%c", payload[i]);
+ } else {
+ printf(".");
+ }
+ }
+ if (payload_len > 64) printf("...");
+ printf("\n");
+ }
+
+ printf("\nParser state: %d\n", ws_parser_get_state(parser));
+
+ } else if (result == 0) {
+ printf("Incomplete frame, need more data\n");
+ printf("Parser state: %d\n", ws_parser_get_state(parser));
+ } else {
+ printf("Parse error\n");
+ printf("Parser state: %d\n", ws_parser_get_state(parser));
+ }
+
+ // 清理
+ ws_parser_destroy(parser);
+}
+
+int main() {
+ printf("WebSocket Parser Standalone Test\n");
+ printf("================================\n");
+
+ // 测试单帧解析
+ test_single_frame();
+
+ // 测试多帧解析
+ test_multiple_frames();
+
+ printf("\nAll tests completed.\n");
+ return 0;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+{
+ "summary": {
+ "total_frames": 9,
+ "total_bytes": 503,
+ "valid_frames": 9,
+ "skipped_frames": 494
+ },
+ "frames": [
+ {
+ "frame_index": 0,
+ "offset": 0,
+ "header": {
+ "fin": 1,
+ "rsv": 3,
+ "rsv_binary": "011",
+ "opcode": "0x02",
+ "opcode_name": "BINARY",
+ "mask": 1,
+ "payload_length": 75
+ },
+ "frame_size": 81,
+ "payload_hex": "B2 CB 2C 65 94 15 47 92 C0 60 81 84 0E 08 10 50 C0 E5 96 4F FF F9 67 FF CB 2C A9 60 60 A0 81 CA 8F 21 91 91 97 FF FF FF C4 64 65 E4 65 FF E6 46 73 23 23 23 32 32 32 32 1F FF F3 23 76 76 76 76 79 38 D3 8B 28 B3 0F 2D A4 E2 CA",
+ "payload_utf8": ",e\u0015G`\u000e\b\u0010POg,``ʏ!deeFs###2222\u001f#vvvvy8Ӌ(\u000f-",
+ "payload_json": null
+ },
+ {
+ "frame_index": 1,
+ "offset": 95,
+ "header": {
+ "fin": 0,
+ "rsv": 3,
+ "rsv_binary": "011",
+ "opcode": "0x08",
+ "opcode_name": "CLOSE",
+ "mask": 1,
+ "payload_length": 50
+ },
+ "frame_size": 56,
+ "payload_hex": "F3 48 C4 DF 18 BB F2 14 F4 28 45 5D 4E 34 E2 CA 3C C0 3A 4C 41 4D 45 33 2E 31 30 30 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA",
+ "payload_utf8": "H\u0018\u0014(E]N4<:LAME3.100",
+ "payload_json": null
+ },
+ {
+ "frame_index": 2,
+ "offset": 151,
+ "header": {
+ "fin": 1,
+ "rsv": 2,
+ "rsv_binary": "010",
+ "opcode": "0x0A",
+ "opcode_name": "PONG",
+ "mask": 1,
+ "payload_length": 42
+ },
+ "frame_size": 48,
+ "payload_hex": "AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA",
+ "payload_utf8": "",
+ "payload_json": null
+ },
+ {
+ "frame_index": 3,
+ "offset": 199,
+ "header": {
+ "fin": 1,
+ "rsv": 2,
+ "rsv_binary": "010",
+ "opcode": "0x0A",
+ "opcode_name": "PONG",
+ "mask": 1,
+ "payload_length": 42
+ },
+ "frame_size": 48,
+ "payload_hex": "AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA FF F3 48",
+ "payload_utf8": "H",
+ "payload_json": null
+ },
+ {
+ "frame_index": 4,
+ "offset": 252,
+ "header": {
+ "fin": 1,
+ "rsv": 7,
+ "rsv_binary": "111",
+ "opcode": "0x08",
+ "opcode_name": "CLOSE",
+ "mask": 0,
+ "payload_length": 52
+ },
+ "frame_size": 54,
+ "payload_hex": "18 4D CC AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA",
+ "payload_utf8": "\u0018M̪",
+ "payload_json": null
+ },
+ {
+ "frame_index": 5,
+ "offset": 306,
+ "header": {
+ "fin": 1,
+ "rsv": 2,
+ "rsv_binary": "010",
+ "opcode": "0x0A",
+ "opcode_name": "PONG",
+ "mask": 1,
+ "payload_length": 42
+ },
+ "frame_size": 48,
+ "payload_hex": "AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA",
+ "payload_utf8": "",
+ "payload_json": null
+ },
+ {
+ "frame_index": 6,
+ "offset": 354,
+ "header": {
+ "fin": 1,
+ "rsv": 2,
+ "rsv_binary": "010",
+ "opcode": "0x0A",
+ "opcode_name": "PONG",
+ "mask": 1,
+ "payload_length": 42
+ },
+ "frame_size": 48,
+ "payload_hex": "AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 81 72 7B 22 68 65 61 64 65 72 22 3A 7B 22",
+ "payload_utf8": "r{\"header\":{\"",
+ "payload_json": null
+ },
+ {
+ "frame_index": 7,
+ "offset": 407,
+ "header": {
+ "fin": 0,
+ "rsv": 2,
+ "rsv_binary": "010",
+ "opcode": "0x02",
+ "opcode_name": "BINARY",
+ "mask": 0,
+ "payload_length": 58
+ },
+ "frame_size": 60,
+ "payload_hex": "22 45 6E 64 53 79 6E 74 68 65 73 69 73 22 2C 22 6D 73 67 22 3A 22 73 75 63 63 65 73 73 22 2C 22 73 74 61 74 75 73 22 3A 32 30 30 30 30 30 30 30 2C 22 74 61 73 6B 5F 69 64 22",
+ "payload_utf8": "\"EndSynthesis\",\"msg\":\"success\",\"status\":20000000,\"task_id\"",
+ "payload_json": null
+ },
+ {
+ "frame_index": 8,
+ "offset": 467,
+ "header": {
+ "fin": 0,
+ "rsv": 3,
+ "rsv_binary": "011",
+ "opcode": "0x0A",
+ "opcode_name": "PONG",
+ "mask": 0,
+ "payload_length": 34
+ },
+ "frame_size": 36,
+ "payload_hex": "37 63 30 31 36 37 61 63 63 30 61 37 32 31 38 37 65 33 64 61 31 31 39 61 36 61 35 61 62 62 33 30 22 7D",
+ "payload_utf8": "7c0167acc0a72187e3da119a6a5abb30\"}",
+ "payload_json": null
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+简化版WebSocket数据解析工具 - 增强版,确保RSV位验证
+"""
+
+import json
+import re
+
+def hex_to_bytes(hex_string):
+ """将十六进制字符串转换为字节"""
+ hex_string = re.sub(r'\s+', '', hex_string)
+ return bytes.fromhex(hex_string)
+
+def get_opcode_name(opcode):
+ """获取操作码名称"""
+ opcode_names = {
+ 0x0: "CONTINUATION",
+ 0x1: "TEXT",
+ 0x2: "BINARY",
+ 0x8: "CLOSE",
+ 0x9: "PING",
+ 0xA: "PONG"
+ }
+ return opcode_names.get(opcode, f"UNKNOWN(0x{opcode:02X})")
+
+def analyze_websocket_frames(hex_data):
+ """分析WebSocket帧,确保只有RSV位为0的帧才有效"""
+ data = hex_data
+ frames = []
+ offset = 0
+ skipped_count = 0
+
+ print(f"开始分析WebSocket数据,总长度: {len(data)} 字节")
+
+ while offset < len(data):
+ if offset + 2 > len(data):
+ break
+
+ # 解析帧头
+ first_byte = data[offset]
+ second_byte = data[offset + 1]
+
+ fin = (first_byte >> 7) & 0x1
+ rsv = (first_byte >> 4) & 0x7
+ opcode = first_byte & 0x0F
+ mask = (second_byte >> 7) & 0x1
+ payload_len = second_byte & 0x7F
+
+ # 验证RSV位 - 只有RSV为0的帧才有效
+ # if rsv != 0:
+ # print(f"跳过无效帧: 偏移={offset}, RSV={rsv:03b} (非0), 第一个字节=0x{first_byte:02X}")
+ # offset += 1 # 跳过1字节,继续搜索
+ # skipped_count += 1
+ # continue
+
+ # 验证操作码是否有效
+ valid_opcodes = [0x0, 0x1, 0x2, 0x8, 0x9, 0xA] # CONTINUATION, TEXT, BINARY, CLOSE, PING, PONG
+ if opcode not in valid_opcodes:
+ print(f"跳过无效帧: 偏移={offset}, 操作码=0x{opcode:02X} (无效), 第一个字节=0x{first_byte:02X}")
+ offset += 1 # 跳过1字节,继续搜索
+ skipped_count += 1
+ continue
+
+ # 计算帧头大小
+ header_size = 2
+ if payload_len == 126:
+ if offset + 4 <= len(data):
+ extended_len = int.from_bytes(data[offset+2:offset+4], 'big')
+ header_size += 2
+ else:
+ extended_len = 0
+ elif payload_len == 127:
+ if offset + 10 <= len(data):
+ extended_len = int.from_bytes(data[offset+2:offset+10], 'big')
+ header_size += 8
+ else:
+ extended_len = 0
+ else:
+ extended_len = payload_len
+
+ if mask:
+ header_size += 4
+
+ total_frame_size = header_size + extended_len
+
+ if offset + total_frame_size > len(data):
+ break
+
+ # 提取负载
+ payload_start = offset + header_size
+ payload_data = data[payload_start:payload_start + extended_len]
+
+ # 尝试解析JSON
+ json_content = None
+ try:
+ if payload_data:
+ json_content = json.loads(payload_data.decode('utf-8'))
+ except:
+ pass
+
+ # 构建帧信息
+ frame_info = {
+ "frame_index": len(frames),
+ "offset": offset,
+ "header": {
+ "fin": fin,
+ "rsv": rsv,
+ "rsv_binary": f"{rsv:03b}", # 添加二进制表示
+ "opcode": f"0x{opcode:02X}",
+ "opcode_name": get_opcode_name(opcode), # 添加操作码名称
+ "mask": mask,
+ "payload_length": extended_len
+ },
+ "frame_size": total_frame_size,
+ "payload_hex": payload_data.hex(' ').upper() if payload_data else "",
+ "payload_utf8": payload_data.decode('utf-8', errors='ignore') if payload_data else "",
+ "payload_json": json_content
+ }
+
+ frames.append(frame_info)
+ print(f"发现有效帧: 偏移={offset}, 操作码={get_opcode_name(opcode)}, 大小={total_frame_size}字节, RSV={rsv:03b}")
+ offset += total_frame_size
+
+ print(f"分析完成: 有效帧={len(frames)}, 跳过帧={skipped_count}")
+ return frames
+
+def main():
+ # 原始十六进制数据
+ hex_data = """B2 CB 25 96 59 64 B2 CB 2C 65 94 15 47 92 C0 60
+ 81 84 0E 08 10 50 C0 E5 96 4F FF F9 67 FF CB 2C
+ A9 60 60 A0 81 CA 8F 21 91 91 97 FF FF FF C4 64
+ 65 E4 65 FF E6 46 73 23 23 23 32 32 32 32 1F FF
+ F3 23 76 76 76 76 79 38 D3 8B 28 B3 0F 2D A4 E2
+ CA 2C C3 DD A6 9D 9C C3 DD 9D 9D 9D 9C D3 8D 38
+ B2 8B 28 B3 FF F3 48 C4 DF 18 BB F2 14 F4 28 45
+ 5D 4E 34 E2 CA 3C C0 3A 4C 41 4D 45 33 2E 31 30
+ 30 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA FF F3 48 C4 EF 1C A4 14 F8 34 18 4D
+ CC AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA AA 81 72 7B 22 68 65 61 64 65 72 22 3A
+ 7B 22 65 76 65 6E 74 22 3A 22 45 6E 64 53 79 6E
+ 74 68 65 73 69 73 22 2C 22 6D 73 67 22 3A 22 73
+ 75 63 63 65 73 73 22 2C 22 73 74 61 74 75 73 22
+ 3A 32 30 30 30 30 30 30 30 2C 22 74 61 73 6B 5F
+ 69 64 22 3A 22 37 63 30 31 36 37 61 63 63 30 61
+ 37 32 31 38 37 65 33 64 61 31 31 39 61 36 61 35
+ 61 62 62 33 30 22 7D"""
+
+ # 转换为字节
+ data = hex_to_bytes(hex_data)
+
+ # 分析帧
+ frames = analyze_websocket_frames(data)
+
+ # 生成输出
+ output = {
+ "summary": {
+ "total_frames": len(frames),
+ "total_bytes": len(data),
+ "valid_frames": len(frames),
+ "skipped_frames": len(data) - len(frames) # 估算跳过的帧数
+ },
+ "frames": frames
+ }
+
+ # 保存到文件
+ with open("websocket_simple_analysis.json", "w", encoding="utf-8") as f:
+ json.dump(output, f, ensure_ascii=False, indent=2)
+
+ print(f"分析完成,共发现 {len(frames)} 个有效WebSocket帧")
+ print("结果已保存到 websocket_simple_analysis.json")
+
+ # 打印前几个帧的摘要
+ for i, frame in enumerate(frames[:5]):
+ print(f"\n帧 {i+1}:")
+ print(f" 偏移: {frame['offset']}")
+ print(f" 大小: {frame['frame_size']} 字节")
+ print(f" FIN: {frame['header']['fin']}")
+ print(f" RSV: {frame['header']['rsv_binary']} ({frame['header']['rsv']})")
+ print(f" 操作码: {frame['header']['opcode']} ({frame['header']['opcode_name']})")
+ print(f" 负载长度: {frame['header']['payload_length']}")
+ if frame['payload_json']:
+ print(f" JSON内容: {frame['payload_json']}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file