GatewayWorker定时器为什么执行了del却没有生效

zk33311

请教各位大神一个问题
 
我用GatewayWorker做了一个websocket定时向客户端发送数据的功能,通过利用定时器定时从某服务器获取数据,并发送给客户端。
 
且客户端可以切换发送数据的内容,每次切换回关掉之前的定时器后,再打开一个新的定时器。但是当我切换过快的话,却发现之前定时器没有被关闭,仍在发送数据,这样相当于发送了两次数据(比如,定时器时间间隔是5s执行一次,这时,出现的情况是相当于5s内会执行两次)。。(我测试了一下,如果我把切换的时间控制在2s的样子,则不会出现这个问题)
 
这是什么原因,应该如何解决?
 
在论坛中看见,说是多进程造成的,那我应该如何去把定时器放在同一个进程中。第一次玩GatewayWorker,还请大神指点一二
 

public static function onClose($client_id)
{
    // 向所有人发送
    global $this_client_id,$closed_data,$change2closed;
    Gateway::sendToAll(json_encode('closing'));
    if ($change2closed === true){
        $preBName = $closed_data['get']['preBName'];
        $pre_timer = $closed_data['get']['add_timer'];
        $BName = $closed_data['get']['BName'];
    }else{
        $preBName = $GLOBALS['client_id_groupName'][$client_id];
        $pre_timer = $GLOBALS[$preBName."_timer"];
    }
    $pre_countGroup =  Gateway::getClientCountByGroup($preBName);
    if ($pre_countGroup==0){
        GateWay::sendToAll(json_encode('To all start_deleting'));
        Gateway::sendToClient($this_client_id,json_encode('start_deleting'));
        $del_result = \Workerman\Lib\Timer::del($pre_timer);
        if ($del_result===false){
            GateWay::sendToAll(json_encode(array(
                'error'         =>  'del error!',
                'preBName'      =>  $preBName,
                'pre_timer'     =>  $pre_timer
            )));
        }
        unset($GLOBALS[$preBName."_timer"]);
        unset($GLOBALS['client_id_groupName'][$client_id]);
    }
    if ($change2closed === true){
        $check_countByGroup = Gateway::getClientCountByGroup($BName);
        if ($check_countByGroup!=0){
            Gateway::joinGroup($this_client_id,$BName);
            Gateway::sendToClient($this_client_id,json_encode(array(
                'type'      => 'addTimer',
                'client_id' => $this_client_id,
                'timer' => $GLOBALS[$BName."_timer"]
            )));
            Events::getXmlInfo($this_client_id,$closed_data,5);
        }else{
            Gateway::joinGroup($this_client_id,$closed_data['get']['BName']);
            Events::getXmlInfo($this_client_id,$closed_data,5);
            //调用定时函数为类的静态方法,具体可参考文档wokerman定时器手册
            $timer = \Workerman\Lib\Timer::add(5,array('Events','getXmlInfo'),array($this_client_id,$closed_data,5));
            $GLOBALS[$closed_data['get']['BName']."_timer"] = $timer;
            Gateway::sendToClient($this_client_id,json_encode(array(
                'type'      => 'addTimer',
                'client_id' => $this_client_id,
                'timer' => $timer
            )));
        }
        $change2closed = false;
        Gateway::sendToClient($this_client_id,json_encode('close_succeed'));
    }
}[/code]
[code] /*当客户端连接上gateway完成websocket握手时触发的回调函数。*/
public static function onWebSocketConnect($client_id,$data){
    $httpReal = ['http://local.test.com','http://mytest.test1.cn'];
    if (array_search($data['server']['HTTP_ORIGIN'],$httpReal) === false){
        Gateway::sendToClient($client_id,"HTTP_ORIGIN为".$data['server']['HTTP_ORIGIN']."与".$httpReal."不一致,请修改httpReal与HTTP_ORIGIN一致");
        Gateway::closeClient($client_id);
    }else{
        global $change2closed;
        $change2closed = false;
        $pre_cid = $data['get']['pre_cid'];
        if ($pre_cid != "null"){//主要用于做同平台账号切换时,通过判断pre_cid(即client_id)是否为null,null则为第一次加载(即首次通过浏览器窗口打开此页面);若果不为空,则关闭这个client
            global $this_client_id,$closed_data;
            $this_client_id = $client_id;    //设置一个全局可供调用的当前client_id供on_Close触发时,可以调用到正在执行中的client_id
            $closed_data = $data;    //设置一个全局可供调用的$closed_data供on_Close触发时,可以调用到本次传过来的$data(主要是使用$data['get']中的数据)
            $change2closed = true;
            Gateway::sendToClient($client_id,json_encode('start closeClient'));
            Gateway::closeClient($pre_cid);
        }else{
            $check_countByGroup = Gateway::getClientCountByGroup($data['get']['BName']);
            Gateway::sendToClient($client_id,json_encode(array(
                'first-load'             =>  '**********************',
                'check_countByGroup'     =>  $check_countByGroup
            )));
            if ($check_countByGroup!=0){
                Gateway::joinGroup($client_id,$data['get']['BName']);
                $GLOBALS['client_id_groupName'][$client_id] = $data['get']['BName'];
                Gateway::sendToClient($client_id,json_encode(array(
                    'type'      => 'addTimer',
                    'client_id' => $client_id,
                    'timer' => $GLOBALS[$data['get']['BName']."_timer"]
                )));
                Events::getXmlInfo($client_id,$data,5);
            }else{
                Gateway::joinGroup($client_id,$data['get']['BName']);
                $GLOBALS['client_id_groupName'][$client_id] = $data['get']['BName'];
                Events::getXmlInfo($client_id,$data,5);
                //调用定时函数为类的静态方法,具体可参考文档wokerman定时器手册
                if ($GLOBALS[$data['get']['BName']."_timer"] === null){
                    $timer = \Workerman\Lib\Timer::add(5,array('Events','getXmlInfo'),array($client_id,$data,5));
                    $GLOBALS[$data['get']['BName']."_timer"] = $timer;
                }
                Gateway::sendToClient($client_id,json_encode(array(
                    'type'      => 'addTimer',
                    'client_id' => $client_id,
                    'timer' => $timer
                )));
            }
        }
    }
}
2602 9 0
9个评论

walkor

这里有一个 全局定时器项目,你可以试下
https://github.com/walkor/global-timer

  • 暂无评论
zk33311

你好,我是在Event.php中的onWebSocketConnect中设置的定时器,我需要在每次建立websocket连接时判断,当前分组是否有client_id在线,如果有,则直接将新的client_id加入该分组,无需再创建定时器,如果该分组没有client_id在线,则新的client_id加入分组,同时创建定时器。

所以,我这种情况,我应该怎么去应用,我看了一下你发我的这个全局定时器,不是很明白在我的项目中应该如何去应用,是否可以详细说一下。
代码如下:
public static function onClose($client_id)
{
// 向所有人发送
global $this_client_id,$closed_data,$change2closed;
Gateway::sendToAll(json_encode('closing'));
if ($change2closed === true){
$preBName = $closed_data['get']['preBName'];
$pre_timer = $closed_data['get']['add_timer'];
$BName = $closed_data['get']['BName'];
}else{
$preBName = $GLOBALS['client_id_groupName'][$client_id];
$pre_timer = $GLOBALS[$preBName."_timer"];
}
$pre_countGroup = Gateway::getClientCountByGroup($preBName);
if ($pre_countGroup==0){
GateWay::sendToAll(json_encode('To all start_deleting'));
Gateway::sendToClient($this_client_id,json_encode('start_deleting'));
$del_result = \Workerman\Lib\Timer::del($pre_timer);
if ($del_result===false){
GateWay::sendToAll(json_encode(array(
'error' => 'del error!',
'preBName' => $preBName,
'pre_timer' => $pre_timer
)));
}
unset($GLOBALS[$preBName."_timer"]);
unset($GLOBALS['client_id_groupName'][$client_id]);
}
if ($change2closed === true){
$check_countByGroup = Gateway::getClientCountByGroup($BName);
if ($check_countByGroup!=0){
Gateway::joinGroup($this_client_id,$BName);
Gateway::sendToClient($this_client_id,json_encode(array(
'type' => 'addTimer',
'client_id' => $this_client_id,
'timer' => $GLOBALS[$BName."_timer"]
)));
Events::getXmlInfo($this_client_id,$closed_data,5);
}else{
Gateway::joinGroup($this_client_id,$closed_data['get']['BName']);
Events::getXmlInfo($this_client_id,$closed_data,5);
//调用定时函数为类的静态方法,具体可参考文档wokerman定时器手册
$timer = \Workerman\Lib\Timer::add(5,array('Events','getXmlInfo'),array($this_client_id,$closed_data,5));
$GLOBALS[$closed_data['get']['BName']."_timer"] = $timer;
Gateway::sendToClient($this_client_id,json_encode(array(
'type' => 'addTimer',
'client_id' => $this_client_id,
'timer' => $timer
)));
}
$change2closed = false;
Gateway::sendToClient($this_client_id,json_encode('close_succeed'));
}
}

public static function onWebSocketConnect($client_id,$data){
$httpReal = [''http://local.test.com','http://mytest.test1.cn'];
if (array_search($data['server']['HTTP_ORIGIN'],$httpReal) === false){
Gateway::sendToClient($client_id,"HTTP_ORIGIN为".$data['server']['HTTP_ORIGIN']."与".$httpReal."不一致,请修改httpReal与HTTP_ORIGIN一致");
Gateway::closeClient($client_id);
}else{
global $change2closed;
$change2closed = false;
$pre_cid = $data['get']['pre_cid'];
if ($pre_cid != "null"){//主要用于做同平台账号切换时,通过判断pre_cid(即client_id)是否为null,null则为第一次加载(即首次通过浏览器窗口打开此页面);若果不为空,则关闭这个client
global $this_client_id,$closed_data;
$this_client_id = $client_id; //设置一个全局可供调用的当前client_id供on_Close触发时,可以调用到正在执行中的client_id
$closed_data = $data; //设置一个全局可供调用的$closed_data供on_Close触发时,可以调用到本次传过来的$data(主要是使用$data['get']中的数据)
$change2closed = true;
Gateway::sendToClient($client_id,json_encode('start closeClient'));
Gateway::closeClient($pre_cid);
}else{
$check_countByGroup = Gateway::getClientCountByGroup($data['get']['BName']);
Gateway::sendToClient($client_id,json_encode(array(
'first-load' => '**',
'check_countByGroup' => $check_countByGroup
)));
if ($check_countByGroup!=0){
Gateway::joinGroup($client_id,$data['get']['BName']);
$GLOBALS['client_id_groupName'][$client_id] = $data['get']['BName'];
Gateway::sendToClient($client_id,json_encode(array(
'type' => 'addTimer',
'client_id' => $client_id,
'timer' => $GLOBALS[$data['get']['BName']."_timer"]
)));
Events::getXmlInfo($client_id,$data,5);
}else{
Gateway::joinGroup($client_id,$data['get']['BName']);
$GLOBALS['client_id_groupName'][$client_id] = $data['get']['BName'];
Events::getXmlInfo($client_id,$data,5);
//调用定时函数为类的静态方法,具体可参考文档wokerman定时器手册
if ($GLOBALS[$data['get']['BName']."_timer"] === null){
$timer = \Workerman\Lib\Timer::add(5,array('Events','getXmlInfo'),array($client_id,$data,5));
$GLOBALS[$data['get']['BName']."_timer"] = $timer;
}
Gateway::sendToClient($client_id,json_encode(array(
'type' => 'addTimer',
'client_id' => $client_id,
'timer' => $timer
)));
}
}
}
}

  • 暂无评论
walkor

代码太乱看不清。

  • 暂无评论
zk33311

请问你能发个邮箱给我不,我发你邮箱 我整理下发给你 看可以吗

  • 暂无评论
zk33311

我修改了一下原贴,把代码站上去了,你看这样子好点不

  • 暂无评论
walkor

全局定时器用法和普通定时器用法一样

  • 暂无评论
zk33311

那我想再问下,我是否还需要像例子中说的($worker->id === 0)去指定进程id呢,如果还需要指定的话,例子中是在onWorkerStart中去指定的进程id,但是我是想在onWebSocketConnect中去指定,这个我如何去拿到类似的$worker这个参数?

  • 暂无评论
zk33311

cal_WebSite\GatewayWorker\vendor\workerman\gateway-worker\src\Lib\GlobalTimer.php on line 40
dor\workerman\gateway-worker\src\Lib\GlobalTimer.php on line 40
Worker process terminated with ERROR: E_ERROR "Class 'Channel\Client' not found in G:\PHPStudy\Local_WebSite\GatewayWorker\vendor\workerman\
gateway-worker\src\Lib\GlobalTimer.php on line 40"
process G:\PHPStudy\Local_WebSite\GatewayWorker\Applications\YourApp\start_businessworker.php terminated and try to restart
accountType none 4 [ok]

我把全局定时器部署后,连接切换时会报这个,请问是什么原因?

  • 暂无评论
zk33311

另外,还有一个很奇怪的问题就是,我现在的GatewayWorker和我的网站使用的是两个不同的站点(即网站域名和js中的ws:xxx:7272的域名不同),部署在两台不同的服务器上时,就会出现这个问题。当我把GatewayWorker和我的网站部署在同一台服务器上(即网站域名和js中的ws:xxx:7272的域名相同)时,则不会出现帖子最先说的发送两次数据的问题

  • 暂无评论
年代过于久远,无法发表评论

zk33311

-15
积分
0
获赞数
0
粉丝数
2019-06-21 加入
🔝