跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Workerman怎么自定义协议_实现input和encode方法详解【详解】

不是必须,但绝大多数自定义场景下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 值没做兜底。这些不会报错,但会让连接看起来“时好时坏”,查起来特别费时间。

相关文章