swoole_websocket_server->push()返回false表示本次推送失败,原因包括fd无效、缓冲区满、数据超长(默认2MB)或发送空字符串;需用exist()和getClientInfo()双重校验fd状态,并开启调试日志定位问题。

为什么 swoole_websocket_server->push() 返回 false
返回 false 表示推送失败,但不等于连接已断——它只说明本次调用未能成功写入 socket 缓冲区。常见原因有:目标 $fd 不存在或已关闭、客户端主动断开未被及时检测、发送缓冲区满(send_yield 未开启)、或数据超长(默认限制 2MB)。
检查 $fd 是否有效且在线
不能只靠“发过消息”就认为 $fd 还活着。Swoole 不会自动清理已断开的连接,需主动验证:
- 调用
$server->exist($fd),返回false说明该$fd已被回收(连接已断且心跳/超时触发了close回调) - 即使
exist()返回true,也不代表可写;可配合$server->getClientInfo($fd)查看websocket_status字段是否为3(WEBSOCKET_STATUS_FRAME,即正常握手完成状态) - 避免在
onClose后仍缓存并尝试向该$fd推送——这是最常见的逻辑漏洞
确认发送内容和配置是否合规
两类硬性限制会导致 push() 直接失败并返回 false:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 数据长度超过
websocket_max_frame_size(默认2097152字节),此时错误日志里会出现"frame too large"—— 需在swoole_websocket_server初始化时显式设置更大的值 - 发送空字符串或
null,push()会静默失败(不报错但返回false),务必在调用前做is_string($data) && strlen($data) > 0校验 - 若启用了
open_http2_protocol或自定义协议,push()不适用,必须用send()+ 手动封帧
启用调试与日志定位真实原因
仅靠返回值无法区分是连接问题还是数据问题。必须打开底层日志:
- 启动服务前设置
swoole_set_process_name('php websocket debug')并开启'log_file' => '/tmp/swoole.log'和'log_level' => SWOOLE_LOG_DEBUG - 复现问题后搜索日志中的
push、fd=xxx、broken pipe、connection reset等关键词 - 特别注意:当客户端快速重连又断开时,可能出现
fd被复用但旧推送尚未完成的情况,此时push()可能操作到新连接的上下文——这也是为什么不能跳过exist()+getClientInfo()双重校验
真正难排查的不是 push 返回 false,而是你以为它该成功的时候它没成功,而日志里又没报错——这时候大概率是 fd 状态判断缺失、缓存了过期连接,或者发了空数据。

















