不是必须,但绝大多数自定义场景下input和encode缺一不可;input用于判断数据包完整性以解决粘包,encode用于序列化返回值确保客户端可解析。

Workerman 自定义协议必须实现 input 和 encode 吗?
不是必须,但绝大多数自定义场景下,这两个方法缺一不可。Workerman 的协议解析流程是:收到原始数据 → 调用 input 判断是否收齐一帧 → 收齐后调用 decode(如果存在)→ 处理业务逻辑 → 返回值交给 encode 序列化发送。如果你跳过 input,TCP 粘包问题会直接导致 onMessage 收到半包或乱包;不实现 encode,返回值会被强制转成字符串(比如数组变 Array),客户端根本没法解析。
input 方法怎么写才不丢包、不卡死?
input 的唯一职责是:告诉 Workerman “当前缓冲区里有没有一个完整的数据单元”。它不能做解析,不能修改缓冲区,不能抛异常,返回值只能是 0(没收到完整包)、正整数(包长度)、false(连接应关闭)。常见错误是返回负数或非数字,会导致 Worker 进程静默退出。
- 定长协议:直接返回固定长度,比如
return 16; - 带包头的变长协议(如前 4 字节是 body 长度):先检查缓冲区是否 ≥ 4,再读出长度
$len = unpack('N', $buffer)[1],最后判断strlen($buffer) >= 4 + $len,满足则返回4 + $len,否则返回0 - 行协议(如 HTTP、Redis):用
strpos($buffer, "\r\n")找分隔符,找到就返回位置 + 2,找不到返回0 - 绝对不要在
input里调用substr或mb_substr截取数据——这是decode的事
encode 方法和 decode 怎么配对才不出错?
encode 的输入是 onMessage 的返回值(或 send() 的参数),输出必须是 string;decode 的输入是 input 切出来的完整包,输出应该是业务能直接用的结构(如数组、对象)。两者类型要严格镜像:如果 decode 返回 ['cmd' => 'login', 'data' => [...]],那 encode 就该接受同样结构并吐出二进制或 JSON 字符串。
- JSON 协议:decode 用
json_decode($buffer, true),encode 用json_encode($data, JSON_UNESCAPED_UNICODE) - 二进制协议:decode 用
unpack拆字段,encode 用pack组包,注意字节序(N大端,V小端)和字段顺序必须完全一致 - 别在
encode里加换行或空格——除非协议明确要求,否则容易被客户端当成脏数据 - 如果
encode返回非 string(比如 null、array),Workerman 会静默转成空字符串,对方收不到任何东西
Workerman 7+ 的协议类写法和老版本有啥关键差异?
Workerman 7 开始强制要求协议类继承 Workerman\Protocols\ProtocolInterface,且 input 和 encode 必须声明为 public,签名也变了:input(string $buffer): ?int、encode(mixed $data): string。老版本允许返回 false 表示断连,新版本得抛 Workerman\Connection\ConnectionException。
- 旧写法
public function input($buffer) { return false; }在 v7+ 会触发致命错误 - 新协议类里,
decode不再是可选方法,如果没定义,Workerman 会把原始 buffer 当作字符串传给onMessage - 路径上,v7+ 的协议类建议放在
app/Protocols/YourProtocol.php,自动加载更稳定,别再扔在vendor里硬改 - 调试时看
Worker::$logFile,重点搜Protocol input returned invalid或encode must return string这类提示
input 返回了不确定值(比如有时 0,有时 false),或者 encode 对 null 值没做兜底。这些不会报错,但会让连接看起来“时好时坏”,查起来特别费时间。









