workerman 5.2.3 自定义协议报错主因是 protocolinterface 未完整实现、input/encode/decode 类型或逻辑错误、粘包处理失当、编解码不可逆、协议绑定失败;需逐层验证接口实现、数据流、收发一致性及类加载。

Workerman 5.2.3 自定义协议报错,核心问题通常不在协议逻辑本身,而在于协议类未正确实现接口、数据流处理时机错位,或底层收发行为与预期不一致。直接看日志往往只显示“onMessage 未触发”或“连接断开”,需从协议注册、输入解析、编码解码三处逐层验证。
确认 ProtocolInterface 是否完整实现
自定义协议必须严格实现 Workerman\Protocols\ProtocolInterface 接口的三个方法:input、encode、decode。缺一不可,且签名不能出错(例如返回类型、参数数量)。
- input 方法必须返回 int(包长度)或 0(继续等待)或 false(关闭连接),不能返回 null 或字符串
- encode 方法接收原始数据(如数组或字符串),必须返回 string 类型的封包结果(如拼接长度头 + 内容)
- decode 方法接收缓冲区中的原始字节流(string),必须返回业务数据(如数组、对象),不能直接 echo 或 var_dump
- 检查是否用了 PHP 8.2+ 的严格类型声明(如 declare(strict_types=1)),导致隐式类型转换失败
检查 input 方法是否能正确识别包边界
粘包/拆包问题在自定义协议中最常见。如果 input 始终返回 0,数据就永远卡在缓冲区;如果返回错误长度,decode 就会收到截断或溢出的数据。
- 在 input 中加 file_put_contents('/tmp/input.log', "raw: ".bin2hex($buffer).", len: ".strlen($buffer)."\n", FILE_APPEND) 查原始字节流
- 确保你约定的包头长度(如前 4 字节为 int32 大端长度)与 C# / Unity 客户端完全一致;PHP 用 unpack('Nlen', $buffer) 解析,不是 V 或 L
- 若客户端发送的是纯文本无长度头,input 应返回 strlen($buffer),即整包接收——但仅适用于单行命令等简单场景
验证 encode/decode 是否双向可逆
协议失效常因 encode 输出和 decode 输入不匹配。典型表现是 onMessage 收到 null、空数组或乱码。
- 写一个独立测试脚本:$data = ['cmd'=>'login','uid'=>1001]; $packed = $protocol->encode($data); $unpacked = $protocol->decode($packed); 确保 $unpacked === $data
- 注意:encode 输出必须是 string;decode 输入是 string,但内容可能含 \0 或非 UTF-8 字节,不要用 json_encode/json_decode 直接处理二进制
- 若使用 Protobuf 或 MsgPack,确认扩展已启用(php -m | grep msgpack),且序列化/反序列化函数调用无异常
排查 Workerman 启动与协议绑定环节
协议类加载失败或绑定错误,会导致 Workerman 回退到默认 Frame 协议,从而行为完全不符预期。
- 确认 Worker 构造时传入了完整类名:new Worker('tcp://0.0.0.0:2345', ['transport' => 'tcp', 'protocol' => \App\Protocols\MyProto::class])
- 检查命名空间和自动加载:use App\Protocols\MyProto; 且该文件路径与 PSR-4 规则一致
- 在 onWorkerStart 中 var_dump(class_exists(\App\Protocols\MyProto::class)),确保类真实可用
- 禁用 opcache(开发期):opcache.enable=0,避免修改协议类后仍加载旧字节码











