我的需求是根据需求给客户端某个用户推送消息,代码如下:
<?php
use Workerman\Worker;
include_once __DIR__ . DIRECTORY_SEPARATOR . '../config.php';
require_once WORKERMAN_WEBSOCKET_API_ROOT . '/Workerman/Autoloader.php';
require_once ROOT_DIR . 'lib/FileMonitor.php';
include_once ROOT_DIR . 'lib/config.php';
include_once ROOT_DIR . 'lib/MySQL.php';
include_once ROOT_DIR . 'lib/SysException.php';
include_once ROOT_DIR . 'lib/ActionException.php';
include_once ROOT_DIR . 'lib/common.php';
include_once H5_API_ROOT . 'include/function.php';
include_once H5_API_ROOT . 'include/action.php';
include_once H5_API_ROOT . 'include/verifyRequest.php';
//方便监控WorkerMan进程状态
Worker::$pidFile = ROOT_DIR . 'logs/workerman.pid';
//输出日志, 如echo,var_dump等
Worker::$stdoutFile = ROOT_DIR . 'logs/stdout.log';
//workerman自身相关的日志,包括启动、停止等,不包含任何业务日志
Worker::$logFile = ROOT_DIR . 'logs/workerman.log';
// 创建一个Worker监听2345端口,使用http协议通讯
$worker = new Worker('websocket://' . $ws_server_config['host'] . ':' . $ws_server_config['port']);
// 启动4个进程对外提供服务
$worker->count = 4;
$worker->name = 'MyWebsocketWorker';
// 新增加一个属性,用来保存uid到connection的映射
$uuidConnections = [];
$worker->onWorkerStart = function ($worker) {
echo "Worker " . $worker->id . " starting...\n";
};
$worker->onConnect = function ($connection) {
echo "new connection " . $connection->worker->id . ' : ' . $connection->id . " from ip " . $connection->getRemoteIp() . "\n";
};
$worker->onMessage = function ($connection, $data) use ($worker) {
$data = parseClientContentToArray($data);
//print_r($data);
if (empty($data['sid'])) {
echo 'sid 参数缺失' . "\r\n";
return;
}
global $uuidConnections;
$uuidConnections[$data['sid']] = $connection;
print_r(array_keys($uuidConnections));
//require_once 'action.php';
switch ($data['act']) {
case 'push_msg_to_individual':
print_r(array_keys($uuidConnections));
if (isset($uuidConnections[$data['data']['tsid']])) {
$result = $uuidConnections[$data['data']['tsid']]->send($data['data']['content']);
if ($result === true) {
echo "消息发送成功\r\n";
} else if ($result === false) {
echo "消息发送失败\r\n";
} else {
echo "发生未知错误\r\n";
}
} else {
echo "目标用户已下线,消息发送失败\r\n";
}
break;
default:
//echo "未匹配到方法\r\n";
break;
}
$connection->send('OK!');
};
$worker->onClose = function ($connection) {
echo "connection " . $connection->id . " closed\n";
};
$worker->onError = function ($connection, $code, $msg) {
echo $connection->id . " error $code $msg\n";
};
// 运行worker
Worker::runAll();
我有一个客户端页面用的 js websocket 连接着这个服务,代码就不上了,另外一个测试页面代码如下:
sendMessageBySidV1([
'sid' => '111111111',
'gid' => '',
'type' => '',
'errcode' => 0,
'msg' => '给某个用户推送消息',
'act' => 'push_msg_to_individual',
'data' => ['tsid' => '1624441757325-0.05429327573496745', 'content' => 'hello 啊!']
]);
我期望的结果是我刷新我这个测试页面会向我的那个客户端页面推送消息。
现在的问题是当我把 $worker->count 设置为大于 1 的时候,会有一定的几率推送消息失败,设置为1不会有问题,看下图:
我知道大概是进程的问题,但是我现在那个 $uuidConnections 是个超全局变量吧,难道每个 worker 读取 $uuidConnections 的值的时候结果会不一样吗?
我记得多进程的话,进程间变量不共享的