workerman 5.2.3 自定义二进制协议需实现含 input、decode、encode 三个 public static 方法的 php 类,置于 protocols 命名空间及 app/protocols/ 目录下;input 判定完整包长度并返回字节数,decode 解析完整包为 php 数据,encode 将 php 数据序列化为带大端头的二进制流;worker 中通过 $worker->protocol = 'protocols\mybinaryprotocol' 启用,须确保自动加载且无实例依赖。

Workerman 5.2.3 自定义二进制协议的核心,是实现一个含 input、decode、encode 三个静态方法的 PHP 类。它不依赖扩展,纯 PHP 实现,适用于长连接、设备上报、实时推送等对性能和包体精简有要求的场景。
协议类结构与存放位置
自定义协议类需放在项目 Protocols 目录下(如 app/Protocols/MyBinaryProtocol.php),并使用命名空间 Protocols:
- 类名任意,但需与文件名一致(如
MyBinaryProtocol) - 必须声明为
public static方法,且全部为静态(static) - 不能有构造函数或实例属性,Workerman 只调用静态方法
关键三方法详解与写法要点
input($buffer):决定“什么时候算收到一个完整包”
- 输入是原始字节流(
$buffer),可能含多个包或半个包 - 典型做法:先读固定长度头部(如前4字节为 body 长度),用
unpack('N', $header)解出总包长(含头) - 若缓冲区不足头部长度 → 返回
0,继续等待 - 若头部已齐但 body 不足 → 返回
0 - 若整个包(头+体)都已就位 → 返回该包总字节数(如
$header_len + $body_len) - 返回负数(如
-1)会强制断开当前连接
decode($buffer):把完整二进制包转成 PHP 可用数据
炫酷的jQuery二进制数字时钟,它的时分秒都是用二进制来表示,绿色表示该位值是1,灰色则表示0,原理是将时钟的时分秒分别实时转换成二进制,然后随着本地时间的更新而实时刷新
- 输入是
input返回长度后截取的完整包(含头+体) - 示例:跳过4字节头,用
substr($buffer, 4)取 body,再json_decode($body, true)或unpack解析结构化字段 - 返回值就是最终传给
onMessage($connection, $data)的$data
encode($data):把 PHP 数据打包成二进制流发出去
- 输入是业务层要发送的内容(如数组)
- 先序列化 body(如
json_encode($data)或pack打包字段) - 再计算 body 长度,拼接4字节大端序包头:
pack('N', strlen($body)) . $body - 返回值将被 Workerman 写入 socket
在 Worker 中启用该协议
创建 Worker 时,直接指定协议类全名(不含命名空间前缀):
use WorkermanWorker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('tcp://0.0.0.0:7788');
$worker->protocol = 'Protocols\MyBinaryProtocol'; // 注意双反斜杠转义
$worker->onMessage = function($connection, $data) {
// $data 已是 decode 后的数组或对象
var_dump($data);
$connection->send(['status' => 'ok', 'seq' => 123]);
};
Worker::runAll();
- 协议类路径必须可自动加载(推荐用 Composer PSR-4 自动加载)
- 若类不在标准命名空间
Protocols下,需确保$worker->protocol指向正确 FQCN - Workerman 5.2.3 对协程友好,
onMessage中可安全 await 协程客户端(如workerman/http-client)
调试与避坑提示
常见问题集中在粘包/断包处理逻辑上:
-
input返回值错(如该返 0 却返了正数)→ 导致 decode 解错位置,数据乱码 - 未严格按网络字节序(大端)打包长度字段 → 客户端/服务端解析不一致
- encode 返回非 string 类型(如 array)→ Workerman 报 warning 并静默丢弃
- 协议类中用了
$this或实例变量 → 因是静态调用,会报 fatal error - 开发期建议加日志:在
input开头打印strlen($buffer),在decode打印bin2hex($buffer)查原始字节










