open_eof_check通过指定EOF标记解决TCP粘包问题,需配合package_eof设置结束符,仅当接收数据末尾包含该标记才触发onReceive回调,适用于文本协议场景。

open_eof_check 是怎么解决 TCP 粘包的
它不靠猜长度、也不靠定时器,而是等一个明确的“句号”——只要收到的数据末尾出现 package_eof 指定的字符串(比如 "\r\n"),Swoole 就认定这是一个完整数据包,立刻触发 onReceive 回调。否则就一直缓存,直到超时或缓冲区满。
这适用于所有以固定结尾符分隔的文本协议,比如你手写的行协议、SMTP、POP3、Redis 原生命令交互(SET key val\r\n)。
- 只检查数据**末尾**是否匹配 EOF,不扫描中间 —— 所以性能高,但一次
onReceive可能带多个包 - 必须和
package_eof配合使用,单独设open_eof_check => true无效 - 对二进制协议基本没用,因为很难保证结尾恰好是某个可控字节序列
为什么开了 open_eof_check 还会收多条消息
因为 open_eof_check 默认只看结尾:客户端连续发了 "a\r\nb\r\n",Swoole 收到后发现末尾是 "\r\n",就整段投递,不会自动切成 "a\r\n" 和 "b\r\n" 两份。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
这时候你需要在业务代码里手动拆分:
$messages = explode("\r\n", $data);
foreach ($messages as $msg) {
if ($msg !== '') {
// 处理单条消息
}
}
- 如果不想自己拆,可以启用
open_eof_split => true,它会从头到尾扫描 EOF 并切分,但 CPU 开销明显上升 -
open_eof_split优先级高于open_eof_check,即使后者为 false,只要前者为 true 就生效 - 别指望
open_eof_check能替代应用层协议解析 —— 它只管“有没有收完”,不管“收的是不是合法命令”
常见配置错误和后果
最常踩的坑不是配错参数名,而是协议两端不一致:
- 服务端设了
package_eof => "\r\n",但客户端发的是"hello world\n"→ 连接卡住,最终超时断开 - 忘了设
package_max_length,恶意客户端发超长无 EOF 数据 → 触发 buffer overflow,连接被强制关闭 - 在 UDP 或 Unix socket 上启用
open_eof_check→ 完全无效,该选项仅对SWOOLE_SOCK_TCP类型有效 - 用
\n作 EOF,但在 Windows 客户端用\r\n发送 → 协议失配,表现就是部分消息永远收不到
open_eof_check 和 open_length_check 怎么选
如果你的协议每条消息开头有固定长度字段(比如前 4 字节表示 body 长度),用 open_length_check 更稳;如果协议天然带结尾标记(像 HTTP header 的空行、自定义日志的换行),open_eof_check 更轻量。
-
open_eof_check启动快、无额外内存开销,但依赖协议格式干净 -
open_length_check对数据内容无要求,但需要客户端严格按“长度+内容”格式发包 - 两者不能同时开启,Swoole 会报错退出
- 实际项目中,建议先用
open_eof_check快速验证协议逻辑,压测时再根据 CPU/延迟数据决定是否切到open_length_check
open_eof_check 当成万能粘包解药,它只是帮你把边界判断下移到了框架层,协议健壮性还得靠两端约定死、写清楚、测到位。

















