Swoole不会自动识别协议格式,必须显式配置set()或setProtocol(),否则onReceive收到的是原始TCP流(粘包/半包);UDP下setProtocol()无效,需用on('packet')手动处理。

直接结论:Swoole 不会自动识别你的协议格式,必须显式配置 set() 或 setProtocol(),否则 onReceive 收到的就是原始 TCP 流(粘包/半包),不是“一调用就一个完整请求”。
为什么 set() 配置 open_eof_check 不生效?
常见现象是开了 open_eof_check、设了 package_eof,但客户端发 10 条 "hello\r\n",服务端 onReceive 里却一次收到 "hello\r\nhello\r\nhello\r\n..." —— 这说明 EOF 拆包根本没触发。
原因通常是:
-
package_max_length没设或设得太小(默认 8192,但若单条数据超长会被截断,导致 EOF 找不到) - 客户端发送时没带真正的
\r\n(比如用了\n却配了package_eof => "\r\n") - 服务端监听的是 HTTP Server 的子端口,但忘了给子端口单独
set()(HTTP Server 主端口的配置不继承给listen()出来的 TCP 端口) -
open_eof_check写成了open_eof_split(旧版遗留字段,新版已废弃,静默忽略)
固定包头协议怎么配 package_length_type?
这是最常用也最容易配错的场景。假设协议是「前 4 字节为 body 长度(大端)」,那么必须严格匹配字节序和字段位置:
-
package_length_type必须填'N'(大端 32 位),不能填'V'或'L',否则 unpack 出来的长度值是错的 -
package_length_offset填0(长度字段从包头第 0 字节开始) -
package_body_offset填4(包体从第 4 字节开始) - 必须同时设置
package_max_length(比如1024 * 1024),否则长度超限会被丢弃
示例配置:
$tcp_port->set([
'package_length_type' => 'N',
'package_length_offset' => 0,
'package_body_offset' => 4,
'package_max_length' => 1048576
]);验证方法:用 pack('N', 123) 在 PHP 客户端构造包头,Wireshark 抓包看是否为 00 00 00 7b。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
UDP 场景下为什么 setProtocol() 没用?
UDP 天然无连接、无顺序、单包独立,Swoole 根本不走 TCP 那套自动拆包逻辑。所有你在 set() 里写的 package_* 配置,在 UDP 上全被忽略——这不是 bug,是设计如此。
正确做法是:
- 删掉所有
package_*配置 - 改用
on('packet')回调,$data就是完整一包原始二进制 - 在回调里手动
unpack()或substr()解析,比如:unpack('Nlen/a*body', $data) - 若需区分多个 UDP 端口,可用
$client_info['server_socket']判断来源 socket
自定义协议解析逻辑该写在哪?
别在 onReceive 里拼字符串做状态机。复杂协议(如 MQTT、RPC)必须把解析逻辑封装成独立类,再注入到服务器实例中。
关键点:
- 解析器要能处理半包:一次
onReceive可能只来半个包头,得缓存并等待下次数据 - 避免在
onReceive中做阻塞操作(如 DB 查询、curl),否则整个 worker 卡住 - 如果协议含魔数(如
0x12345678),只能用package_start_symbol,但它只支持单字节,多字节会静默失败 - WebSocket 服务器完全不支持
setProtocol(),协议已被固定,自定义解析只能在onMessage里手动做
真正容易被忽略的是:package_max_length 不只是防攻击,它还决定底层缓存区大小。设太小,大包直接被截断;设太大,万级连接时内存爆炸。这个值必须根据实际业务最大单包体积 + 并发连接数综合估算,不能拍脑袋填 2MB。

















