定时器覆盖问题

netslang

public function onMessage($connection, $data)
{
global $worker;
$connection->lastMessageTime = time();
$data = json_decode($data, true);
$_SESSION['hotel_price'] = '';
switch($data['type']){
case 'login':
$where['id'] = $data['id'];
$where['token'] = $data['token'];
$id = Db::name('business')->where($where)->value('id');
if($id){
$connection->uid = $id;//设置当前客户端id
$worker->uidConnections[$connection->uid] = $connection;//保存到服务器里
$connection->send('{"type":"login","msg":"登录成功"}');
$timer = new Timer();
$connection->timer_id = $timer->add('10',function()use($connection,$data){
$connection->send('{"type":"ping"}');
});
}else{
$connection->timer_id = '';
$connection->uid = $data['id'].$data['token'];
$worker->uidConnections[$connection->uid] = $connection;//保存到服务器里
$connection->send('{"type":"login","msg":"登录失败"}');
$connection->close();
}
break;
}
}

如果用户多点了一次login的话 定时器就会形成两个ping到客户端了 各位大神 怎么解决?

1902 1 0
1个回答

taozywu

首先你需要多看下文档,定时器不建议写在onMessage回调。

从你代码中大致得出定时器主要做一件事:那就是心跳检测。

如下为大概示例:

<?php
 
require_once __DIR__ . '/Workerman/Autoloader.php';
 
 
use Workerman\Worker;
use Workerman\Lib\Timer;

$worker = new Worker('tcp://0.0.0.0:1234');

$worker->onWorkerStart = function($worker) {
    // 防止开多进程
    if ($worker->id === 0) {
        Timer::add(10, function()use($worker) {
            foreach($worker->connections as $connection) {
                $connection->send('{"type":"ping"}');
            }
        });
    }
};
 
$worker->onConnect = function($connection) {
};

$worker->onMessage = function($connection, $data) {
    global $worker;
    $connection->lastMessageTime = time();
    $data = json_decode($data, true);
    $_SESSION['hotel_price'] = '';
    switch ($data['type']) {
        case 'login':
            $where['id'] = $data['id'];
            $where['token'] = $data['token'];
            $id = Db::name('business')->where($where)->value('id');
            if ($id) {
                $connection->uid = $id; //设置当前客户端id
                $worker->uidConnections[$connection->uid] = $connection; //保存到服务器里
                $connection->send('{"type":"login","msg":"登录成功"}');
            } else {
                $connection->timer_id = '';
                $connection->uid = $data['id'] . $data['token'];
                $worker->uidConnections[$connection->uid] = $connection; //保存到服务器里
                $connection->send('{"type":"login","msg":"登录失败"}');
                $connection->close();
            }
            break;
    }
};

// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START')) {
    Worker::runAll();
}
  • netslang 2020-08-27

    如果不放到onMessage里,那用户send验证账户密码怎么做,验证登录密码后 我们要实时返回数据给用户呢,我现在的情况是 可能用户多点了一次login 我们的服务器会返回两次数据,重复了 怎么样避免这样的问题呢?

  • taozywu 2020-08-27

    if($success) {
    $connection->send(json);
    }
    类似这样就行了。

  • netslang 2020-08-27

    @753: 我们会定时返回数据给用户呢? 比如有消息回来我们要推给用户撒 推给用户的同时必须要这个用户是登录成功的

  • taozywu 2020-08-31

    @7358:onMessage 绑定好用户bindUid。然后在定时器通过判断获取到然后sendToUid

  • taozywu 2020-08-31

    @7358:可以把数据保存在redis中,在定时器中读取一下。

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