workerman 守护进程方式启动出现的问题

李海峰

大神,请麻烦帮忙看下这个问题,
正常用 php start.php start 这种启动方式时 对某个uid 发送消息是没有问题的,
但是用 php start.php start -d 这种守护进程方式启动时 对某个uid发送信息 内容是错误的,比如正常应该发送300 但是发送的是100或200的值。
逻辑为 workerStart里写个定时器 定时从redis里取uid返回状态,
uid为key, value分别为 100, 200, 300
 start_io.php

use Workerman\Worker;
use Workerman\WebServer;
use Workerman\Lib\Timer;
use PHPSocketIO\SocketIO;

include __DIR__ . '/vendor/autoload.php';

//redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// 全局数组保存uid在线数据
$uidConnectionMap = [];

// PHPSocketIO服务
$sender_io = new SocketIO(2120);
// 客户端发起连接事件时,设置连接socket的各种事件回调
$sender_io->on('connection', function($socket) {
    // 当客户端发来登录事件时触发
    $socket->on('login', function($uid) use($socket) {
        global $uidConnectionMap;
        //已经登录过了
        if(isset($uidConnectionMap)) {
            return;
        }

        // 更新对应uid的在线数据
        $uid = (string)$uid;
        // 将这个连接加入到uid分组,方便针对uid推送数据
        $socket->join($uid);
        $socket->uid = $uid;
        $uidConnectionMap = $uid;
    });

    // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
    $socket->on('disconnect', function () use($socket) {
        global $uidConnectionMap;
        if(isset($socket->uid)) {
            unset($uidConnectionMap);
        } else {
            return;
        }
    });
});

// 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
$sender_io->on('workerStart', function() {
    // 监听一个http端口
    $inner_http_worker = new Worker('http://0.0.0.0:2121');

    // 执行监听
    $inner_http_worker->listen();

    // 一个定时器,定时向所有uid推送当前uid在线数及在线页面数
    Timer::add(5, function() {
        global $sender_io, $uidConnectionMap, $redis;
        if(!empty($uidConnectionMap)) {
            foreach($uidConnectionMap as $uid) {
                $result = $redis->hget('workers', $uid);
                $result = intval($result);
                //$sender_io->to($uid)->emit('new_msg', json_encode());
                // 对 uid 发送 message
                if($result > 0) {
                    $sender_io->to($uid)->emit('new_msg', json_encode());
                    unset($uidConnectionMap);
                }
            }
        }
    });
});

if(!defined('GLOBAL_START')) {
    Worker::runAll();
}
6573 1 0
1个回答

walkor 打赏

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);redis初始化放到onWorkerStart里试下,如果放在启动入口文件直接初始化redis连接则属于在主进程初始化了redis连接,每个子进程都复用这个连接会导致数据混乱。onWorkerStart里初始化连接这样属于每个子进程初始化连接,每个进程拥有自己的redis连接,互相不影响
 

  • 李海峰 2018-12-10

    问题好像解决了,我再观察下,非常感谢,辛苦了~

年代过于久远,无法发表回答
×
🔝