从 MQTT 客户端获取已连接的客户端 ID 列表

问题描述 投票:0回答:7

作为连接到 mosquitto 的 mqtt 客户端,是否可以检索也连接到代理的客户端 ID 列表?

client mqtt
7个回答
10
投票

实现此目的的一种方法是让客户端每次连接代理时发布主题为“status/client-id”且有效负载为“1”的消息,并在断开连接时发布有效负载为“0”的消息。

然后在服务器(代理)端,设置另一个客户端订阅主题“status/#”,当它收到任何这样的消息时,将客户端 ID 和负载(连接或未连接)存储到数据库中。

然后您可以读取数据库准确知道哪个客户端在线或离线。


6
投票

方法一:在客户端逻辑中处理

正如@user1048839所说,使用客户的

LWT
并在线发布消息, 维护自定义主题的客户状态。 下标此主题并自行维护客户列表。

if pub

retain
msg,一旦sub就会得到客户端列表。

方法二:更改mosquitto经纪商代码

官方代码不支持online_list,
所以我修补了 mosquitto 1.5.4,添加了 2 个自定义系统主题:

1.网上名单

mosquitto_sub -i DDD -v -t '$SYS/broker/chen_list'
$SYS/broker/chen_list
0 - CLOUD0_19108
1 - EEE
2 - DDD

2.线上/线下活动

mosquitto_sub -i DDD -v -t '$SYS/broker/chen_state/#'
$SYS/broker/chen_state/DDD 1
$SYS/broker/chen_state/EEE 1
$SYS/broker/chen_state/CLOUD0_19108 1
$SYS/broker/chen_state/EEE 0
$SYS/broker/chen_state/EEE 1

// if pub

retain
msg, sub 这个topic可以获取所有客户端的在线状态(在payload中)。

在github上测试源代码:

4-在线列表

5-线上活动


5
投票

您可能可以通过 BASH 命令 netstat、grep 以及 awk(如果需要)获取此信息。如果 Mosquitto 使用端口 1883 那么以下内容会告诉你你想要什么:

sudo netstat -n | grep :1883

2
投票

没有。

在 mosquitto 邮件列表上讨论这个问题可能会更好:https://launchpad.net/~mqtt-users


2
投票

一个好的解决方法是让客户(如果可能)定义最后的遗嘱和遗嘱(LWT)。您的服务器将订阅一个特殊主题,LWT 将发布到该主题,并假定所有客户端都在线,除非它们发布到该主题。

MQTT Last Will Testament 的目的或用途是什么?


1
投票

好吧,我现在使用 PHP 脚本创建了一个解决方法:它启动 mosquitto 代理,读取输出,如果有人连接或断开连接,它会向代理发送一个包含已连接客户端的 XML 字符串。 (发布的代码有点简化,因为我另外查询数据库以获取有关用户的更多信息)

<?php 
    require ('SAM/php_sam.php');
    if (!$handle = popen('mosquitto 2>&1', 'r')) {
        die('could not start mosquitto');
    }
    function usersToXML($users) {
        $xml = '<?xml version="1.0"?><userlist>';
        foreach ($users as $user) {
            $xml.= '<user>' . '<id><![CDATA[' . $user->id . ']]></id>' . '</user>';
        }
        $xml.= '</userlist>';
        return $xml;
    }
    function updateBroadcast($users) {
        sleep(1);
        ob_start();
        $conn = new SAMConnection();
        $conn->Connect(SAM_MQTT, array(SAM_HOST => '127.0.0.1', SAM_PORT => 1883));
        $conn->Send('topic://broadcast', (object)array('body' => usersToXML($users)));
        $conn->Disconnect();
        ob_end_clean();
    }
    while ($line = fread($handle, 2096)) {
        echo $line;
        if (preg_match('/New client connected from .+ as user_(\d+)./', $line, $regs)) {
            $user = (object)array('id' => $regs[1]);
            $connectedUsers[$user->id] = $user;
            updateBroadcast($connectedUsers);
        } else if (preg_match('/Received DISCONNECT from user_(\d+)/', $line, $regs) || preg_match('/Client user_(\d+) has exceeded timeout, disconnecting./', $line, $regs) || preg_match('/Socket read error on client user_(\d+), disconnecting./', $line, $regs)) {
            if (isset($connectedUsers[$regs[1]])) {
                unset($connectedUsers[$regs[1]]);
                updateBroadcast($connectedUsers);
            }
        }
    }
    pclose($handle);
?>

1
投票

如果您访问服务器上的mosquitto.log文件,您可以获取在线/已连接客户端的列表。

  1. 读取添加到日志文件中的最后一行并使用正则表达式对其进行处理以访问设备ID。
const Tail = require('tail-file');

const mosquittoLogFilePath = '/var/log/mosquitto/mosquitto.log';
const mytail = new Tail(mosquittoLogFilePath, line => {
  if (line.includes("PINGRESP")){
      const deviceId = translatePingResponse(line);
      if(deviceId){
        processOnlineClient(deviceId);
      }
  }
});

  1. 使用正则表达式进行翻译
function translatePingResponse(line){
    const regex = /\w* Sending PINGRESP to (\w*-\w*-\w*-\w*-\w*)/g;
    const found = [...line.matchAll(regex)];
    if(
      found[0] &&
      found[0][1]
    ){
      const manufactureId = found[0][1];
      return manufactureId;
    }else{
      console.log(`unknown line -> ${line}`);
    }
  
}
  1. 执行流程
function processOnlineClient(deviceId){
    console.log(`${deviceId} is Online`);
}

查看我创建的这个存储库 📦 nodeJS 中的 msqtConnectedClinets

© www.soinside.com 2019 - 2024. All rights reserved.