直接调用 $connection->close() 即可断开 tcp 连接,它会触发 shutdown() 和 close() 并随后执行 onclose 回调;onclose 仅是连接已关闭后的通知,不可用于主动断连。

直接调用 $connection->close() 就能断开 TCP 连接
Workerman 的每个客户端连接都封装为一个 Connection 对象,只要拿到这个对象(比如在 onMessage 或 onConnect 回调里),调用它的 close() 方法即可立即关闭该 TCP 连接。它会触发底层 socket 的 shutdown() 和 close(),并最终触发 onClose 回调。
onClose 不是关闭动作,只是连接已关闭后的通知
很多人误以为在 onClose 里写逻辑就能“执行关闭”,其实不是:onClose 是被动回调,发生在连接**已经断开之后**,此时再调用 $connection->close() 无效,甚至可能报错(如 “Connection is closed”)。真正需要主动断连的场景,必须在 onMessage、onConnect 或定时器中调用。
- 错误写法:
$worker->onClose = function($connection) { $connection->close(); };—— 没有意义,连接早已关闭 - 正确时机举例:收到特定指令(如
"quit")、认证失败、心跳超时、发送缓冲区满且无法恢复 - 注意:
close()是异步非阻塞的,调用后不会等待 TCP FIN 完成,但连接状态会立刻变为关闭中
关闭前要不要清空发送缓冲区?看场景
默认情况下,$connection->close() 会尝试把应用层发送缓冲区(maxSendBufferSize)里还没发出去的数据先 flush 掉,再断连。但如果缓冲区积压严重(比如客户端卡死、网络中断),这个过程可能阻塞几秒甚至更久——而 Workerman 的事件循环不能被阻塞。
- 想“立即断开,丢弃未发数据”:先调用
$connection->destroy()(强制销毁 socket 句柄),再unset相关引用 - 想“尽量发完再断”:保持默认
close()行为,但建议配合onBufferFull和onBufferDrain做流控,避免缓冲区无限膨胀 - 常见坑:
maxSendBufferSize设得过大(如 10MB),又没监听onBufferFull,会导致内存暴涨或 close 延迟显著
客户端异常断连时,服务端怎么感知并清理资源?
真实网络中,客户端可能直接断电、杀进程、切网,不会发 FIN 包。Workerman 不会立刻知道,得靠心跳机制探测。单纯依赖 onClose 是不可靠的。
- 必须实现心跳:在
onConnect中启动定时器,例如每 30 秒发一次 ping,连续 3 次无 pong 就$connection->close() - 别只靠
onError:TCP 层错误(如 ECONNRESET)会触发它,但静默断连不会 - 清理动作要放在
onClose里:删用户 session、从在线列表移除、释放绑定的自定义属性(如$connection->uid) - 注意:
onClose中不能做耗时操作(如同步写 DB),否则拖慢整个 Worker 进程;应投递到异步任务或记录日志后快速返回











