不能。同一个 worker 实例无法同时监听 http 和 websocket 协议,因协议解析器不同且构造时已绑定;正确做法是创建多个 worker 实例并共享上下文,如连接池或变量,实现单进程多协议服务。

不能。同一个 Worker 实例无法同时监听 HTTP 和 WebSocket 两种协议的端口。
Workerman 的 Worker 类在初始化时就绑定了协议和地址端口,例如:
$http = new Worker('http://0.0.0.0:8080');
$ws = new Worker('websocket://0.0.0.0:2346');
这两者是完全独立的 Worker 实例,底层使用不同协议解析器(HTTP 解析器 vs WebSocket 握手+帧解析器),不能混用。试图用一个实例启动两种协议会直接报错或无法建立有效连接。
但你可以轻松实现“单进程内同时提供 HTTP 和 WebSocket 服务”,只需创建多个 Worker 实例,并让它们共享内存、协同工作:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
✅ 正确做法:多实例 + 共享上下文
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// HTTP 服务:处理 API、登录、推送触发等
$http = new Worker('http://0.0.0.0:8080');
$http->count = 4;
// WebSocket 服务:长连接通信
$ws = new Worker('websocket://0.0.0.0:2346');
$ws->count = 4;
// 【关键】共享全局变量(如客户端连接池)
$ws->connections = []; // 所有 WebSocket 连接存这里
$ws->onConnect = function ($connection) use ($ws) {
$ws->connections[$connection->id] = $connection;
};
$ws->onClose = function ($connection) use ($ws) {
unset($ws->connections[$connection->id]);
};
$http->onMessage = function ($connection, $request) use ($ws) {
// 例如:收到 /api/broadcast 请求,向所有 WebSocket 客户端广播
if ($request->path === '/api/broadcast' && $request->method === 'POST') {
$data = json_decode($request->post, true);
foreach ($ws->connections as $conn) {
$conn->send(json_encode(['type' => 'broadcast', 'content' => $data['msg']]));
}
$connection->send("Broadcast sent to " . count($ws->connections) . " clients");
} else {
$connection->send("OK");
}
};
Worker::runAll();
✅ 进阶:动态监听(同一子进程内新增端口)
若需更灵活控制(比如 HTTP 启动后才决定是否开启 WebSocket 端口),可在 onWorkerStart 中调用 listen():
$main = new Worker('text://0.0.0.0:2015'); // 占位用的主 Worker
$main->count = 4;
$main->onWorkerStart = function ($worker) {
// 每个子进程动态创建 WebSocket Worker(PHP ≥ 7.0)
$ws_inner = new Worker('websocket://0.0.0.0:2346');
$ws_inner->reusePort = true; // 必须设为 true,避免端口冲突
$ws_inner->onMessage = function ($conn, $data) {
$conn->send("Echo: $data");
};
$ws_inner->listen(); // 在当前进程监听,不启新进程
};
Worker::runAll();
⚠️ 注意:
-
reusePort = true是 PHP 7.0+ 多进程复用同一端口的必要条件; - 动态监听的
$ws_inner不继承$main->count,它只在当前子进程中运行 1 个实例; - 它与
$main在同一进程,可直接共享变量、闭包引用、静态属性等。
❌ 常见误区
- 把
'http://0.0.0.0:8080'和'websocket://0.0.0.0:2346'写进同一个new Worker(...)构造函数 → 语法错误; - 试图用
$worker->protocol = 'websocket'切换协议 → 不生效,协议由构造参数锁定; - 在全局作用域调用
$inner->listen()→ 无效,必须在onWorkerStart或运行时调用。
不复杂但容易忽略。










