Workerman 5.2.3 分隔符协议通过指定字节序列(如"\n")标记消息边界以解决粘包/拆包,需实现input(返回完整消息长度或0)、decode(清洗解析含分隔符数据)、encode(追加分隔符)三个静态方法,示例JsonNL协议以换行符分隔JSON消息。

Workerman 5.2.3 实现分隔符式自定义协议,核心是用一个明确的字节序列(如 "\n"、"\r\n" 或自定义字符串)标记消息边界,解决 TCP 粘包/拆包问题。这种方式简单可靠,适合文本类协议或调试场景,无需解析长度字段或魔数。
协议类需实现的三个静态方法
Workerman 要求自定义协议类必须包含 input、decode 和 encode 三个静态方法,全部位于同一命名空间下(推荐 Protocols),且类名需符合 PSR-4 自动加载规范。
- input(string $buffer): int|false —— 判断缓冲区中是否已有完整消息。扫描 $buffer 是否包含分隔符;若找到,返回从开头到分隔符末尾的总字节数(含分隔符);若未找到,返回 0,表示继续等待数据。
-
decode(string $buffer): mixed —— 对已截取的完整原始数据(含分隔符)做清洗和解析。通常用
trim($buffer, "\n")去掉分隔符,再用json_decode或直接作为字符串使用。 -
encode(mixed $data): string —— 将业务层返回的数据(如数组或字符串)转为可发送的格式,并追加分隔符。例如
json_encode($data) . "\n"。
一个可用的 JsonNL 协议示例
假设协议名为 JsonNL,约定每条消息是合法 JSON 字符串,以换行符 "\n" 结尾(且 JSON 内部不出现该字符):
文件路径:app/Protocols/JsonNL.php
namespace Protocols;
class JsonNL
{
public static function input(string $buffer): int|false
{
$pos = strpos($buffer, "\n");
if ($pos === false) {
return 0;
}
return $pos + 1; // 包含 \n 自身
}
public static function decode(string $buffer): array|string|null
{
$content = rtrim($buffer, "\n");
return json_decode($content, true) ?: $content;
}
public static function encode(mixed $data): string
{
if (is_string($data)) {
return $data . "\n";
}
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
}
}
服务端启用该协议
在 Worker 启动代码中,将协议类名传给监听地址:
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('tcp://0.0.0.0:7777', [
'protocol' => Protocols\JsonNL::class
]);
$worker->onMessage = function ($connection, $data) {
// $data 已是 decode 后的结果(数组或字符串)
var_dump($data);
$connection->send(['status' => 'ok', 'received' => $data]);
};
Worker::runAll();
注意:Workerman 5.2.3 默认支持自动加载 Protocols 命名空间下的类,无需手动 require;若目录结构不同,请确认自动加载配置正确。
客户端发送注意事项
客户端必须严格遵守协议格式,每条消息结尾添加对应分隔符:
- PHP socket 客户端示例:
fwrite($fp, json_encode(['cmd'=>'ping']) . "\n"); - Python 示例:
sock.send(b'{"cmd":"ping"}\n') - 避免多发、漏发或错用分隔符(如混用
"\r\n"但服务端只识别"\n")
分隔符协议不适用于二进制数据或含分隔符内容的场景;若需更高鲁棒性,建议升级为长度前缀协议。

















