使用Workerman实现WebSocket关闭时发消息及跨连接推送问题
Workerman WebSocket 常见问题解决方案
问题1:onClose回调中调用$connection->send()无效
onClose回调触发时,TCP连接已经完全断开,此时无法再通过$connection->send()向客户端发送数据。如果需要在连接关闭前给客户端发送消息,需在连接尚未关闭的时机处理:
处理方式1:客户端主动关闭时提前发送
当客户端发起关闭请求(比如发送特定指令或WebSocket关闭帧),在onMessage中先发送消息再关闭连接:
private function onMessage($connection, $data) { // 假设客户端发送"close"表示请求关闭连接 if ($data === 'close') { // 先发送关闭提示 $connection->send("连接即将关闭,再见!"); // 主动关闭连接 $connection->close(); } // 其他消息逻辑处理 }
处理方式2:服务端主动关闭前发送
如果是服务端主动触发连接关闭,在调用close()方法前先执行send():
// 比如在某个业务逻辑中需要关闭连接 $connection->send("服务端将关闭本次连接"); $connection->close();
问题2:无法向其他连接发送消息
核心原因是没有正确维护所有活跃的连接实例,单进程模式下可通过类属性维护连接池:
步骤1:维护连接池
在类中添加属性存储所有连接,在onConnect时加入,onClose时移除:
// 类属性定义 private $connections = []; private function onConnect($connection) { // 给每个连接分配唯一标识 $connection->id = uniqid(); $this->connections[$connection->id] = $connection; } private function onClose($connection) { // 移除已关闭的连接 if (isset($this->connections[$connection->id])) { unset($this->connections[$connection->id]); } }
步骤2:实现向其他连接发送消息的方法
遍历连接池,排除当前发送者,向其他连接发送消息:
private function broadcastToOthers($fromConn, $message) { foreach ($this->connections as $conn) { // 跳过消息发送者自身 if ($conn !== $fromConn) { $conn->send($message); } } }
调用示例
在onMessage中调用广播方法:
private function onMessage($connection, $data) { // 向其他连接广播当前用户的消息 $this->broadcastToOthers($connection, "其他用户说:{$data}"); }
注意:如果是多进程模式(
count > 1),进程间内存不共享,不能用类属性维护连接池,需要借助Redis等外部存储来实现跨进程的连接管理。
内容的提问来源于stack exchange,提问作者denismart
相关产品推荐
相关产品推荐

