Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
必须用swoole搭建websocket长连接服务端实现实时推送,启动监听9501端口的服务器实例,通过广播或单播(内存映射/redis)向指定用户推送消息,并支持mysql、redis或信号等方式触发外部事件推送。

要在PHP项目中让服务器主动把新订单、聊天消息或股价变动实时推送给在线用户,而不是让用户反复刷新页面或轮询接口,就得用Swoole搭建一个长连接服务端。它不依赖Apache或Nginx的HTTP请求周期,能维持成千上万的WebSocket连接并即时广播数据。
启动基础WebSocket服务端
第一步是创建一个监听9501端口的WebSocket服务器实例,这是所有推送功能的入口点。
执行:php swoole_server.php 启动脚本,确保没有报错“Class 'Swoole\WebSocket\Server' not found”,否则说明Swoole扩展未正确安装或PHP版本低于7.2。
写入以下代码并保存为 swoole_server.php:
<?php <br>$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);<br>$server->on("open", function ($server, $request) {<br> echo "客户端 {$request->fd} 已连接\n";<br>});<br>$server->on("message", function ($server, $frame) {<br> echo "收到消息: {$frame->data}\n";<br>});<br>$server->on("close", function ($server, $fd) {<br> echo "客户端 {$fd} 已断开\n";<br>});<br>$server->start();
实现消息广播给所有在线用户
当某用户发来一条消息,你需要把它立刻发给其他所有人——不是只回给他自己,也不是只存数据库后等别人拉取。
在 message 回调里,遍历 $server->connections 数组,对每个合法连接描述符(fd)调用 $server->push()。
注意:必须先用 is_callable([$server, 'push']) 或 try-catch 判断连接是否仍活跃,否则向已关闭的fd推送会触发警告并中断当前协程。
替换原 message 回调为:
$server->on("message", function ($server, $frame) {<br> $data = $frame->data;<br> foreach ($server->connections as $fd) {<br> if ($server->isEstablished($fd)) {<br> $server->push($fd, "【广播】{$data}");<br> }<br> }<br>});
按用户身份精准单播推送
聊天系统、订单通知或客服工单,往往要求只推给指定人,比如“张三下单了”只通知对应设计师,不惊动其他用户。
方法一:内存映射表维护 fd 与业务ID关系
① 在 open 回调中解析 URL 参数或握手头里的 token,提取 userId:parse_str($request->get['token'] ?? '', $params); $userId = $params['uid'] ?? 'guest';
② 建立全局数组 $userFdMap = [];,连接建立时存:$userFdMap[$userId] = $request->fd;
③ 推送时查表:
if (isset($userFdMap[$targetUserId]) && $server->isEstablished($userFdMap[$targetUserId])) {<br> $server->push($userFdMap[$targetUserId], $msg);<br>}
方法二:使用 Redis 存储 fd 映射(适合多进程/多机器部署)
写入:$redis->hSet('user_fd_map', $userId, $request->fd);
读取:$fd = $redis->hGet('user_fd_map', $targetUserId);
【关键前提】 必须在 close 回调中同步删除该 fd 记录,否则会推送失败或占用无效连接。
接入外部事件触发实时推送
真实业务中,推送动作通常由MySQL插入、Redis发布、定时任务或API调用触发,而非仅靠WebSocket客户端发消息。
方法1:用 Swoole\Table 实现跨Worker进程通信
定义共享内存表:$table = new Swoole\Table(1024); $table->column('msg', Swoole\Table::TYPE_STRING, 2048); $table->create();
在 worker 进程中写入:$table->set("trigger_123", ['msg' => '订单123已支付']);
在 manager 或 task 进程中读取并广播。
方法2:监听 Redis Pub/Sub 频道
启动一个独立的 PHP 进程(非 server 子进程),执行:
$redis->subscribe(['order_paid'], function ($redis, $channel, $msg) use ($server) {<br> foreach ($server->connections as $fd) {<br> $server->push($fd, "新支付:{$msg}");<br> }<br>});
方法3:用 Swoole\Process + IPC 向主 server 进程发送信号
子进程执行 kill -USR1 $masterPid,主进程注册 swoole_process::signal(SIGUSR1, $callback) 处理逻辑。










