2026-09-18-cq2-real-tcp-wire-codec-design.md 4.3 KB

CQ2 TCP 真实帧编解码改造设计

目标

让 Python SDK 的 TCP transport 与当前 macOS 客户端的已验证帧格式一致,替换旧的“24 字节裸头 + 可选 XXTEA”假设。此改造只完成可由二进制和心跳样本证明的帧层;不宣称游戏登录或任务协议已经可用。

已验证的线协议

客户端发送与接收路径分别调用 Encode6BitBuf 和 Decode6BitBuf。

outbound = Encode6BitBuf(header36) + body
inbound  = Decode6BitBuf(first_48_bytes) + remaining_body

明文头固定为 9 个 little-endian int32(36 字节):

offset 字段 证据/用途
0 pre 心跳样本为 0
4 msg_id 接收实现从该偏移读取消息号
8 recog 心跳样本为时间值
12 param1 业务参数
16 param2 业务参数
20 param3 业务参数;心跳样本为 149
24 codec 接收路径据此决定是否解压 body
28 body_len 接收路径据此读取 body
32 sequence 客户端发送时递增写入

Encode6BitBuf 的输出为 48 字节。其字符范围为 0x3c..0x7b;因此 TCP 帧没有 XXTEA 加密,也没有独立的“高两位 SData”位流。

组件设计

transport/encode6.py

提供无运行时 Lua 依赖的、表驱动的 encode6 与 decode6。置换表从已归档的客户端提取表复制为 Python 常量或受版本控制的二进制资源。该模块只负责字节转换。

transport/framing.py

定义真实 FrameHeader:9 个字段、36 字节明文、48 字节线头。

  • encode_frame(...) 产生完整 wire frame:48 字节编码头加 body。
  • decode_header(...) 只接收 48 字节 wire header,返回真实头。
  • decode_frame(...) 检查 body_len 后返回真实 header 和 body。
  • 公开常量同时区分 PLAIN_HEADER_SIZE = 36 与 WIRE_HEADER_SIZE = 48,防止调用方再把 24 当作线上边界。

codec != 0 的 body 解压行为不在本变更实现;接收端应明确报出不支持的 codec,而不能把压缩数据误当业务 body。

transport/tcp.py

TcpClient 使用 48 字节作为读缓冲边界,并在发送时分配递增 sequence。保留现有 send(msg_id, recog, param1, param2, param3, body) 业务接口;增加可选的 pre、codec 和显式 sequence 测试入口仅供低层诊断。

不再调用 xxtea.encrypt。transport/xxtea.py 保留为资源/历史兼容模块,但文档必须明确它不属于游戏 TCP 帧。

初始 sequence 的生产取值尚未由可复现会话证明,因此 transport 构造器显式接收 initial_sequence,默认 0;真实登录调用必须传入被抓包验证的初值,不能伪装为已知常量。

login/game.py 与高层入口

不修改或扩展推测的 CS 104/100/101 序列。相关 docstring 和错误信息改为:帧层已实现;CS2001 body、sequence 初值、服务器 body codec 和后续业务状态机仍待同版本真实会话验证。高层入口继续拒绝将 mock 流程当成实际游戏登录。

测试与验收

  1. golden test:归档的 36 字节心跳头必须编码为精确的 48 字节真实样本,反向解码必须还原。
  2. frame test:body 必须原样拼接,header 的 body_len 与 body 字节数一致。
  3. stream test:TCP mock server 将 wire frame 分段发送时,客户端仍能完整解出一帧。
  4. sequence test:连续发送的 sequence 递增;指定初值可复现。
  5. 旧 XXTEA 测试删除或迁移为独立资源加密测试,不能再作为 TCP 正确性的证据。
  6. 实际验收需要新鲜、授权的真实会话:验证 CS2001 的完整 payload、初始 sequence、body codec 和服务器响应。没有该证据时,SDK 只能声明“帧层已验证”。

非目标

  • 不破解或实现 XXTEA 32→16 映射。
  • 不重放过期登录包,不保存账号、JWT 或抓包中的敏感正文。
  • 不宣称任一游戏内任务消息的 body schema 已验证。

风险与回滚

此改造会改变 encode_frame 的返回格式,从旧的 24B 裸头改为真实 wire 格式。该 SDK 当前没有已验证的真实 TCP 使用者,且高层入口本来就会拒绝进入 TCP 登录,故以协议正确性优先。若调用方仍需要旧 mock 格式,应在测试中使用本地 fixture,而不是保留错误的生产 transport。