作为连接到 mosquitto 的 mqtt 客户端,是否可以检索也连接到代理的客户端 ID 列表?
实现此目的的一种方法是让客户端每次连接代理时发布主题为“status/client-id”且有效负载为“1”的消息,并在断开连接时发布有效负载为“0”的消息。
然后在服务器(代理)端,设置另一个客户端订阅主题“status/#”,当它收到任何这样的消息时,将客户端 ID 和负载(连接或未连接)存储到数据库中。
然后您可以读取数据库准确知道哪个客户端在线或离线。
正如@user1048839所说,使用客户的
LWT
并在线发布消息,
维护自定义主题的客户状态。
下标此主题并自行维护客户列表。
if pub
retain
msg,一旦sub就会得到客户端列表。
官方代码不支持online_list,
所以我修补了 mosquitto 1.5.4,添加了 2 个自定义系统主题:
mosquitto_sub -i DDD -v -t '$SYS/broker/chen_list'
$SYS/broker/chen_list
0 - CLOUD0_19108
1 - EEE
2 - DDD
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上测试源代码:
您可能可以通过 BASH 命令 netstat、grep 以及 awk(如果需要)获取此信息。如果 Mosquitto 使用端口 1883 那么以下内容会告诉你你想要什么:
sudo netstat -n | grep :1883
没有。
在 mosquitto 邮件列表上讨论这个问题可能会更好:https://launchpad.net/~mqtt-users
一个好的解决方法是让客户(如果可能)定义最后的遗嘱和遗嘱(LWT)。您的服务器将订阅一个特殊主题,LWT 将发布到该主题,并假定所有客户端都在线,除非它们发布到该主题。
好吧,我现在使用 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);
?>
如果您访问服务器上的mosquitto.log文件,您可以获取在线/已连接客户端的列表。
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);
}
}
});
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}`);
}
}
function processOnlineClient(deviceId){
console.log(`${deviceId} is Online`);
}
查看我创建的这个存储库 📦 nodeJS 中的 msqtConnectedClinets。