Skip to content

2026-06-09 分包协议 7 项优化修复

变更概述

cPacketProtocolcWinSock 的分包协议实现进行全面审查,修复 2 个 Bug、1 个安全风险、1 个逻辑缺陷、3 个设计问题。

修复详情

1. 心跳绕过协议编码(严重 Bug)

问题:心跳数据通过 m_oSocket.SendArray baHB 直接发送原始字节,未经 Encode 编码。但接收端统一走 Decode 解码。若心跳帧恰好在正常消息碎片中间到达,会导致协议状态机混乱(如 ppLengthHeader 误将心跳字节当成长度头解析)。

修复cWinSock.cls 心跳发送改为 Me.SendData baHB,确保心跳数据经过协议编码,收发两端一致。

2. 2 字节长度头 Encode 溢出(严重 Bug)

问题:VB6 的 Integer 是有符号的(-32768~32767),2 字节头实际能表示 0~65535。当 lDataLen > 32767 时,CInt(lDataLen) 抛出运行时错误。

修复cPacketProtocol.cls Encode 方法:

  • 增加 lDataLen > 65535 校验,超限直接 ERR.Raise
  • lDataLen > 32767 时映射到 lDataLen - 65536 写入 Integer
  • 大端模式使用 lDataLen(Long)计算而非 nLen(Integer)

3. 大端 4 字节解析溢出(Bug)

问题ParseLengthHeader 中大端 4 字节解析 m_baRecvBuffer(0) * &H1000000,当首字节 >= 128 时结果符号位为 1,变成负数。

修复:改用 (m_baRecvBuffer(0) And &H7F) * &H1000000 取低 7 位,再用 Or &H80000000 恢复最高位。

4. 缺少最大包/缓冲区限制(安全风险)

问题:原实现中最大包限制 10MB 硬编码、不可配置,非法长度时静默丢弃缓冲区无通知,缓冲区累积无上限(攻击者可发大量不完整包耗尽内存)。

修复cPacketProtocol.cls 新增:

  • MaxPacketSize 属性(默认 1MB)— 单包最大大小,超限报错丢弃
  • MaxBufferSize 属性(默认 4MB)— 缓冲区累积上限,防内存耗尽
  • ExtractLengthHeaderMessages 中用 MaxPacketSize 替代硬编码 10MB
  • Decode 合并缓冲区前检查 MaxBufferSize
  • 超限时抛出明确错误信息而非静默丢弃

cWinSock.cls 新增 MaxPacketSize/MaxBufferSize 代理属性,TCP/UDP 客户端自动继承。

5. UDP 跳过分包协议(功能缺失)

问题:UDP 模式下收到的数据完全不走 cPacketProtocol.Decode,用户设置了 PacketProtocol 也不会生效。

修复cWinSock.cls m_oSocket_OnReceive 中 UDP 分支:

  • UDP 客户端创建时继承服务端的协议配置(含 MaxPacketSize/MaxBufferSize)
  • 收到数据报后检查客户端是否启用协议,若启用则 Decode 后触发 MessageArrival
  • 无协议时保持原有 UserData + DataArrival 路径

6. FixedLength 静默截断(设计问题)

问题:数据超长时直接截断,不报错也不通知,调用方无法知道数据被裁剪。

修复:数据超长时直接 ERR.Raise 报错,不再静默截断。

7. MessageArrival + DataArrival 双触发(易用性问题)

问题:分包模式下每条完整消息同时触发两个事件。如果用户同时监听两个事件并都调用 GetData,第二次调用会拿到空数据。

修复:协议模式下只触发 MessageArrival,移除了 DataArrival 的兼容触发。无协议模式下仍触发 DataArrival(向后兼容)。事件注释已更新说明。

修改文件

cPacketProtocol.cls

改动位置
新增 m_lMaxPacketSize / m_lMaxBufferSize 成员变量声明区
新增 MaxPacketSize / MaxBufferSize 属性Properties 区
Class_Initialize 初始化默认值(1MB / 4MB)Initialize
Encode ppLengthHeader 增加溢出校验和 Integer 映射Encode 方法
Encode ppFixedLength 超长改为报错Encode 方法
ParseLengthHeader 大端 4 字节无符号解析ParseLengthHeader
ExtractLengthHeaderMessages 用 MaxPacketSize 替代硬编码 + 报错ExtractLengthHeaderMessages
Decode 合并缓冲区前检查 MaxBufferSizeDecode 方法

cWinSock.cls

改动位置
新增 MaxPacketSize / MaxBufferSize 代理属性Properties 区
MessageArrival 事件注释更新事件声明
心跳发送改为 Me.SendData baHBm_oHeartbeat_Tick
TCP OnAccept 客户端继承 MaxPacketSize/MaxBufferSizem_oSocket_OnAccept
UDP 分支支持协议解码 + 继承配置m_oSocket_OnReceive
协议模式移除 DataArrival 双触发m_oSocket_OnReceive

设计.md

新增"分包协议设计要点"章节,记录协议类型、安全限制属性、事件模型、心跳一致性、UDP 支持等设计决策。

VB6及其LOGO版权为微软公司所有