swoole长连接本质是fd持续注册于reactor事件循环且未被显式关闭或超时踢出,需配置heartbeat_check_interval与heartbeat_idle_time并配合客户端心跳包才能真正可靠维持。

长连接不是“一直不关”,而是“按需保持”;短连接不是“不能复用”,而是“用完即弃”。Swoole里选哪种,关键看业务是否需要服务端主动推送、是否高频交互、是否能承受连接数压力。
长连接在Swoole中如何被真正维持
很多人以为只要不调用 $server->close($fd) 就算长连接——这是错的。Swoole的TCP长连接本质是:连接建立后,FD被持续注册进Reactor事件循环,且未被显式关闭或超时踢出。但若客户端静默、服务端无心跳机制,操作系统或中间设备(如NAT网关)可能在几分钟内单向断连,而Swoole还“以为它在线”。
必须配合以下配置才能让长连接真正可靠:
-
heartbeat_check_interval设为 10(秒),表示每10秒扫描一次在线连接 -
heartbeat_idle_time设为 30(秒),表示某连接最后一次收包时间距今超30秒就自动close - 二者差值要留余量,避免因网络抖动误杀连接
- 客户端也得发心跳包(比如
{"type":"ping"}),不能只靠服务端单方面检测
短连接在Swoole中其实很少“手动实现”
Swoole本身面向高并发长连接场景设计,swoole_http_server 默认启用 keep-alive(HTTP长连接),而纯 swoole_server(TCP/UDP)压根不内置短连接模式——你得自己在 onReceive 里处理完立刻调用 $server->close($fd),才算一次短连接交互。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
这种模式的问题很直接:
- 频繁
accept+close会抬高系统调用开销 - 每个连接都要走完整TCP三次握手+四次挥手,延迟明显上升
- 大量TIME_WAIT状态堆积,容易触发
bind: address already in use错误 - 除非是极低频、极偶发的指令类请求(如设备固件升级触发通知),否则不推荐
WebSocket长连接和原生TCP长连接怎么选
别被“WebSocket更高级”带偏。两者在Swoole里都是长连接,但协议层和适用边界完全不同:
- 用
swoole_websocket_server:适合浏览器直连、需要兼容前端WebSocketAPI 的场景,比如聊天室、实时看板。它自动处理握手、帧解析、ping/pong,但payload有固定格式开销 - 用
swoole_server(TCP):适合App、IoT设备、游戏客户端等自定义协议场景,二进制/JSON/Protobuf都可自由约定,性能更高、控制更细,但你要自己写粘包处理、心跳逻辑、断线重连策略 - 注意:
swoole_websocket_server底层仍是TCP长连接,但它在HTTP Upgrade阶段就完成了协议切换,之后所有通信都走WebSocket帧;而裸TCP连接从一开始就是二进制流,没有协议协商过程
连接数暴涨时最容易被忽略的三个点
当你的长连接服务从几百FD涨到几万FD,问题往往不出在逻辑,而在底层资源和配置漏项:
- Linux默认
ulimit -n是1024,必须提前调大(如ulimit -n 65535),否则新连接直接被拒绝,错误日志里只显示accept() failed, Too many open files - Swoole的
worker_num不宜设过高(比如 >32),否则进程间FD共享、内存映射反而成瓶颈;优先调大reactor_num(建议设为CPU核数的1–2倍)提升事件分发能力 - 每个连接都会占用内存(缓冲区+PHP对象),若客户端长期空挂却不发心跳,仅靠
heartbeat_idle_time被动清理不够;应在onReceive中对非法包、超长包、高频无效包做即时拦截并close,防止单个恶意连接拖垮整机










