一个模块绑定多台设备,指令通过模块发送,即多台设备的clientId都一样,该如何判断设备在线情况?

dou号

我有一些设备,是统一通过同一个4G模块来发送指令,即这些设备的的clientid是一样,但是发送过来的指令会携带具体的设备id,此时该如何判断具体某台设备的在线情况呢?目前想法是在onMessage里面,等收到设备的登录指令时,根据不同的设备id,创建对应的一分钟定时器,然后监听设备的心跳指令,如果某台设备的心跳指令及时发送过来,则删除该设备的定时器,同时再创建一个新的定时器,如此反复,如果一分钟内没有收到对应设备的心跳指令,则执行业务逻辑更新数据库设备的状态为离线,这样反复创建定时器可以吗
业务逻辑

241 2 1
2个回答

不败少龙

为什么不是设备id去绑定clientid呢

  • dou号 6天前

    因为多个设备是通过公用同一个模块来发送指令,即这些设备的clientid都一样,如果用设备id去绑定,执行Gateway::bindUid,那么之前绑定的设备id会被挤掉

  • 不败少龙 6天前

    只要重新绑定clientid就会变,通过设备id去查询在线状态,发生指令;即便是多个设备同样的指令也是要单独一个个的发

  • dou号 6天前

    是要单独一个个发,可是这些设备是通过同一个模块发送过来的,我这边onmessage里面打印的数据显示的clientId全都是一样的

  • dou号 6天前

    比如有十台设备,发送了十个登录指令过来,这十个登录指令里面的设备id不一样,但是clientId都一样

  • 不败少龙 6天前

    看看你是怎么进行设备绑定的,按理说不一样clientId才对,贴一下你绑定的代码

  • dou号 6天前

    这些设备全部是通过同一个模块端口发送出来的,所以clientId一样

  • 不败少龙 6天前

    Gateway::bindUid($client_id,$id) 是这样绑定的吗?

  • dou号 6天前

    是的

  • 不败少龙 6天前

    用Gateway::getClientIdByUid方式去打印每个设备的clientId值是不是一样的

  • dou号 6天前

    文档里面说:uid与client_id是一对多的关系,系统允许一个uid下有多个client_id,但是一个client_id只能绑定一个uid,如果绑定多次uid,则只有最后一次绑定有效。
    用Gateway::getClientIdByUid打印发现之前绑定的uid没有了

  • 不败少龙 6天前

    返回一个数组,数组元素为与uid绑定的所有在线的client_id。如果没有在线的client_id则返回一个空数组。

    此方法可以判断一个uid是否在线。

    注意:返回值为与uid绑定的所有在线的client_id数组。因为已经下线的client_id会自动与uid解绑,所以已经下线的client_id不会出现在返回值中。

  • dou号 6天前

    是的,这些设备全部同个一个端口发送,就会导致前一个设备刚刚绑定,当后一个设备登录指令发送过来,就会把前一个给挤掉

  • 不败少龙 6天前

    是的,都是重新绑定,生成新的client_id,多个设备不会存在一样的client_id

  • dou号 6天前

    问题就出在这里,我的多个设备是通过同一个端口来发送指令的,他们在gatewayworker这边的clientid都是一样的,这样就导致了每个端口有且只有一台设备可以在线,所以我想用端口id来绑定clientid,然后用定时器来监控心跳,判断具体设备的在线情况,想问这种频繁的创建和删除定时器是否支持

  • 不败少龙 6天前

    gatewayworker里面是有心跳检测的

  • dou号 5天前

    好的,谢谢

shiroi

可以参考这个,设置一个时间间隔,超出时间如果没有接收到onMessage则默认为关闭状态

use Workerman\Connection\TcpConnection;

class BaseSocket
{
    /** @var int 设置心跳间隔 */
    const HEARTBEAT_TIME = 50;

    /**
     * 启动服务执行
     * @param Worker $worker
     * @return void
     */
    public function onWorkerStart(Worker $worker)
    {
        Timer::add(10, function () use ($worker) {
            $time_now = time();
            foreach ($worker->connections as $connection) {
                // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线
                if ($time_now - $connection->lastMessageTime > self::HEARTBEAT_TIME) {
                    $connection->onLine = 0; //设置为离线
                }
            }
        });
    }

    public function onMessage(TcpConnection $connection, $data)
    {
        //处理数据完成后记录上次收到消息的时间
        $connection->lastMessageTime = time();
        //设置为在线
        $connection->onLine = 1;

    }
}
  • dou号 5天前

    你好,我在Events里面使用Timer定时器,通过use \Workerman\Timer;引用,但是提示找不到该文件,我使用的是Gatewayworker,请问你知道这是什么原因吗

  • shiroi 5天前

    你应该先看看有没有安装workerman依赖 composer require workerman/workermanhttps://www.workerman.net/doc/workerman/install/install.html 说明文档有写。如果还是没有解决问题的话可以发一下代码尝试让大家看看并解决其问题

  • dou号 5天前

    哈哈,问题解决了,路径找到了,use \Workerman\Lib\Timer这样就可以了,谢谢解答

  • shiroi 5天前

    好的

×
🔝