discard_timeout_packets 是 swoole server 控制是否丢弃已关闭连接残留数据包的布尔选项,默认 true;设为 false 可能导致 onreceive 处理失效连接的脏数据,引发协议错乱或崩溃。

discard_timeout_packets 是什么
discard_timeout_packets 是 Swoole Server 配置中的一个布尔型选项,控制当 TCP 连接已关闭(如客户端断开),但内核缓冲区里还有未读取的残留数据包时,Swoole 是否直接丢弃这些“过期”数据包。
它不干预连接建立或心跳逻辑,只影响「连接已不可用但数据还在路上」这种边缘状态下的数据处理策略。默认值为 true,即丢弃;设为 false 会尝试继续读取并触发 onReceive 回调(哪怕连接已 close)。
为什么开启 discard_timeout_packets 能避免 onReceive 拿到脏数据
当客户端异常断网(比如 kill 进程、拔网线)、未发 FIN 包就消失,服务端 socket 可能仍处于 ESTABLISHED 状态短暂时间,而内核缓存中还残留着几 KB 的未 ACK 数据。若此时设置 discard_timeout_packets => false,Swoole 会在后续轮询中把这些残包当作新消息传给 onReceive —— 但此时连接句柄实际已失效,$server->getClientInfo($fd) 可能返回 false,甚至触发 onClose 后又来一条 onReceive,造成协议解析错乱或空指针访问。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 典型表现:
onReceive收到长度非零的数据,但$server->connection_info($fd)返回null或报错Invalid fd - 常见于高并发短连接 + 客户端非优雅退出场景(如小程序快速切页、HTTP/1.1 keep-alive 中断)
- 设为
true(默认)后,Swoole 在检测到连接不可写/不可读时,会主动清空该fd对应的接收缓冲区,跳过投递
discard_timeout_packets 和 heartbeat_check_interval 的关系
两者作用域不同,但协同影响连接清理质量:heartbeat_check_interval 决定多久检查一次心跳超时,触发 onClose;而 discard_timeout_packets 决定在 onClose 触发前或刚触发后,是否还处理残包。
- 若
heartbeat_check_interval设得过大(如 60 秒),discard_timeout_packets => true也无法立刻阻止残包投递——因为连接状态还没被标记为“超时”,Swoole 仍视其为有效连接 - 真正起效需要配合合理的
heartbeat_idle_time(例如 30 秒)和较短的heartbeat_check_interval(如 10 秒),让连接能较快进入“待关闭”状态,此时discard_timeout_packets才有机会介入丢弃 - 注意:WebSocket 模式下,Swoole 会自动启用心跳机制;TCP 模式需手动实现,此时
discard_timeout_packets的意义更关键
什么时候应该设为 false
极少数需要“尽最大努力收完最后一点数据”的场景,比如:
- 自定义长连接协议中,客户端强制断连前会先发一个
FIN_PACKET标记,服务端必须收到才能做事务回滚 - 调试阶段想观察所有进来的原始字节流,包括断连瞬间的残包(仅限开发环境)
- 你已确保
onReceive内部做了if (!$server->connection_info($fd)) return;的防御性检查
生产环境几乎不需要关掉它。一旦关闭,就必须在 onReceive 开头加连接有效性校验,否则容易因 $fd 失效导致 Segmentation fault 或 PHP Warning:swWorker_onTask: connection#xxx is closed。










