workerman 5.2.3 中限制自定义协议单包最大长度需双层控制:一是在协议类 input 方法中解析包头并校验总长,超限返回 false;二是全局设置 tcpconnection::$maxpackagesize 做兜底;二者缺一不可,且不可依赖 textprotocol 相关配置。

Workerman 5.2.3 中限制自定义协议的单包最大长度,核心在于**双层控制**:既要通过协议类的 input 方法主动识别并拒绝超长包,也要配合全局连接级的 maxPackageSize 做兜底防护。两者缺一不可,否则仍可能被恶意数据拖垮内存。
在自定义协议类中用 input 方法校验包长
这是最直接、最可控的方式。你的协议类必须实现 input 静态方法,并在其中解析出完整数据包长度,再与预设上限比对:
- 假设你采用「4 字节包头 + 实际内容」的常见格式,先检查缓冲区是否至少有 4 字节;不够就返回
0,等待后续数据 - 从头 4 字节解出 body 长度(注意用
unpack('N', $buffer)转网络字节序),加上包头本身,得到总包长 - 若总包长超过你设定的上限(如
1024 * 1024,即 1MB),立即返回false—— Workerman 会断开该连接 - 若包长合法且缓冲区足够,返回总包长度;若不够,仍返回
0
设置 Connection::$maxPackageSize 全局兜底
这个静态属性是 Workerman 内部对每个连接接收数据的硬性限制,独立于协议逻辑,属于最后一道防线:
- 在 Worker 初始化前设置,例如:
TcpConnection::$maxPackageSize = 1024 * 1024; - 它作用于所有使用该连接类型的协议(包括自定义协议),只要
input返回的包长超过此值,连接就会被强制关闭 - 注意:它不替代
input的校验,因为input可以在解析阶段就提前拒绝(比如发现包头异常),而maxPackageSize是在input返回长度后才做比对
避免 TextProtocol 的坑,别混用
如果你原本用的是 TextProtocol,切勿以为设置了 max_package_size 和 strict_mode 就万事大吉——那是 Text 协议专用配置,对自定义协议无效:
- 自定义协议完全绕过 TextProtocol 的换行扫描逻辑,
max_package_size参数不会被读取 - 必须靠你自己在
input里解析长度并判断,不能依赖协议类外部传参 - 如果误把自定义协议当成 TextProtocol 使用,超长无换行数据仍会持续堆积缓冲区,直到 OOM
额外建议:加 CRC 或魔数提升健壮性
单纯靠长度限制还不够,网络抖动或设备异常可能导致数据错位。建议在协议设计时加入基础校验:
- 包头起始加 2 字节魔数(如
0xAA55),input中先校验魔数是否存在,避免错位解析 - 包尾加 CRC16 校验和,在
decode阶段验证,不通过则丢弃整包(可选,但推荐) - 这样即使攻击者伪造长度字段,也大概率因魔数或 CRC 不匹配被拦截,进一步降低风险











