使用Workerman从后端PHP脚本向WebSocket客户端发消息失败排查
排查步骤与解决方案
1. 确认HTTP Worker是否正常启动并监听
- 检查
server.php中HTTP Worker的初始化代码,确保端口、协议正确,且与WebSocket Worker一同启动:$http_worker = new Worker('http://0.0.0.0:8081'); $http_worker->count = 1; // 根据需求设置进程数 // 临时添加日志,验证事件是否触发 $http_worker->onMessage = function($conn, $data) { file_put_contents('http_worker.log', date('Y-m-d H:i:s') . ' 收到请求: ' . $data . PHP_EOL, FILE_APPEND); // 后续发送逻辑 }; $ws_worker = new Worker('websocket://0.0.0.0:8080'); // WebSocket相关逻辑... Worker::runAll(); // 必须调用,启动所有Worker - 启动服务后,执行
ps aux | grep workerman查看进程,确认HTTP Worker进程存在。
2. 验证CURL请求是否到达HTTP Worker
- 执行CURL请求后,查看
http_worker.log是否有日志写入:- 若无日志:检查CURL请求的目标IP/端口是否与HTTP Worker监听一致;排查防火墙/端口占用问题;添加
var_dump(curl_error($ch))查看CURL报错信息。 - 有日志:说明HTTP Worker已收到请求,问题出在后续消息发送逻辑。
- 若无日志:检查CURL请求的目标IP/端口是否与HTTP Worker监听一致;排查防火墙/端口占用问题;添加
3. 解决WebSocket连接的跨进程访问问题
Workerman不同Worker进程的内存相互隔离,若HTTP Worker与WebSocket Worker为不同进程,直接遍历WebSocket Worker的$worker->connections或全局数组会为空,需用Channel组件实现进程间通信:
- 安装Channel组件:
composer require workerman/channel - 在
server.php中启动Channel服务:use Workerman\Channel\Server; // 启动Channel服务,端口可自定义 new Server('0.0.0.0', 2206); - WebSocket Worker订阅广播频道:
$ws_worker->onWorkerStart = function($worker) { \Workerman\Channel\Client::connect('127.0.0.1', 2206); // 收到频道消息时广播给所有WebSocket客户端 \Workerman\Channel\Client::on('broadcast', function($msg) use($worker) { foreach($worker->connections as $conn) { // 检查连接状态是否正常 if($conn->status == \Workerman\Connection\TcpConnection::STATUS_ESTABLISHED) { $conn->send($msg); } } }); }; - HTTP Worker发布消息到频道:
$http_worker->onMessage = function($conn, $data) { // 解析请求数据(以POST表单为例) parse_str($data, $post); $msg = $post['msg'] ?? ''; if(empty($msg)) { $conn->send('false'); return; } // 连接Channel并发布消息 \Workerman\Channel\Client::connect('127.0.0.1', 2206); \Workerman\Channel\Client::publish('broadcast', $msg); $conn->send('true'); };
4. 检查消息发送逻辑的正确性
- 若使用单进程模式,确认WebSocket连接是否被正确存储与清理:
// WebSocket Worker的onConnect事件 $ws_worker->onConnect = function($conn) { global $ws_connections; $ws_connections[$conn->id] = $conn; }; // onClose事件移除无效连接 $ws_worker->onClose = function($conn) { global $ws_connections; unset($ws_connections[$conn->id]); }; - 发送消息时务必检查连接状态:
foreach($ws_connections as $conn) { if($conn->status == \Workerman\Connection\TcpConnection::STATUS_ESTABLISHED) { $conn->send($msg); } }
5. 验证CURL请求格式
确保CURL发送的数据格式与HTTP Worker解析逻辑匹配:
- POST表单格式的CURL示例:
$ch = curl_init('http://127.0.0.1:8081'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['msg' => '后端推送消息'])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); // 检查CURL错误 if(curl_errno($ch)) { echo 'CURL错误: ' . curl_error($ch); } curl_close($ch); - JSON格式的CURL示例:
$ch = curl_init('http://127.0.0.1:8081'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['msg' => '后端推送消息'])); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); // HTTP Worker中解析:$data = json_decode($data, true);
内容的提问来源于stack exchange,提问作者Khristyan
相关产品推荐
相关产品推荐

