最简路径是用原生 workerman 启动单进程 websocket 服务并内存维护连接列表:新建 pushserver.php,写入约30行代码,设 count=1,通过 $_server['connections'] 全局共享连接池,业务中遍历发送即可实时推送。

要在服务端不依赖客户端轮询、直接向已连接的前端推送消息,最简路径是用原生 Workerman 启动一个单进程 WebSocket 服务,并在内存中维护连接列表,通过遍历发送。
启动一个单进程 WebSocket 服务
第一步:新建文件 PushServer.php,放在项目根目录或任意可执行位置。
第二步:写入以下最小可行代码(仅 30 行左右,无框架依赖):
```php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$ws_worker = new Worker('websocket://0.0.0.0:2888');
$ws_worker->count = 1;
$ws_worker->connections = [];
$ws_worker->onConnect = function ($connection) {
$connection->uid = uniqid('u_');
$connection->send('已连接,分配 uid:' . $connection->uid);
$_SERVER['connections'][$connection->uid] = $connection;
};
$ws_worker->onMessage = function ($connection, $data) {
echo "收到消息:{$data}\n";
};
$ws_worker->onClose = function ($connection) {
if (isset($connection->uid)) {
unset($_SERVER['connections'][$connection->uid]);
}
};
Worker::runAll();
```
注意:【必须设为单进程】,即 $ws_worker->count = 1。多进程下连接分散在不同子进程,无法跨进程访问 $connection 对象,主动推送必然失败。
从 PHP 其他地方触发推送
方法一:命令行临时推送(调试最快)
新开终端,执行:php -r "file_get_contents('http://127.0.0.1:2888/push?msg=hello');" —— 这种方式需额外加 HTTP 路由层,不推荐。
方法二:直接调用全局连接池(推荐,零额外依赖)
在你业务逻辑中(比如控制器、定时任务、回调函数里),插入这段推送代码:
```php
if (isset($_SERVER['connections']) && !empty($_SERVER['connections'])) {
foreach ($_SERVER['connections'] as $conn) {
if ($conn instanceof \Workerman\Connection\TcpConnection && $conn->isConnected()) {
$conn->send(json_encode(['type'=>'notice','content'=>'系统消息:时间'.date('H:i:s')]));
}
}
}
```
这一步不需要重启服务,只要 PushServer.php 正在运行且连接未断开,就能立刻送达。连接池存在 $_SERVER 超全局变量中,是单进程下最轻量的共享方式。
前端建立连接并监听
新建一个 HTML 文件,放入以下代码并用浏览器打开:
```html
<script><br>const ws = new WebSocket('ws://127.0.0.1:2888');<br>ws.onopen = () => console.log('已连接');<br>ws.onmessage = e => console.log('收到推送:', e.data);<br></script>
```
确保浏览器地址栏是 http:// 或 https:// 开头(不能是 file://),否则 WebSocket 会因跨域策略被拦截。
此时后端任意位置执行上一步的 foreach 推送,前端控制台就会实时打印消息。











