As a mqtt client connected to mosquitto is it possible to retrieve a list of client IDs who are also connected to the broker?
method I: handle in client logic
as @user1048839 says, use client's LWT
& online publish msg,
maintain client status on a custom topic.
subscript this topic & maintain client list self.
if pub retain
msg, once sub will get the client list.
method II: change mosquitto broker code
official code not support online_list,
so I patched mosquitto 1.5.4, add 2 custom sys topic:
1. online list
mosquitto_sub -i DDD -v -t '$SYS/broker/chen_list'
$SYS/broker/chen_list
0 - CLOUD0_19108
1 - EEE
2 - DDD
2. online/offline event
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 this topic can get all clients online state (in payload).
test source code on github:
cmake
to build on windows –
Hateful one way to implement this is let the client publish a message with topic "status/client-id" and payload "1" every time when it connects the broker, and with payload "0" when it disconnects.
Then on the server(broker) side, setup another client subscribe to the topic "status/#", when it gets any message like this, store the client-id and payload(connected or not) into database.
then you can read the database to know exactly which client is online or offline.
method I: handle in client logic
as @user1048839 says, use client's LWT
& online publish msg,
maintain client status on a custom topic.
subscript this topic & maintain client list self.
if pub retain
msg, once sub will get the client list.
method II: change mosquitto broker code
official code not support online_list,
so I patched mosquitto 1.5.4, add 2 custom sys topic:
1. online list
mosquitto_sub -i DDD -v -t '$SYS/broker/chen_list'
$SYS/broker/chen_list
0 - CLOUD0_19108
1 - EEE
2 - DDD
2. online/offline event
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 this topic can get all clients online state (in payload).
test source code on github:
cmake
to build on windows –
Hateful You could presumably get this information via the BASH commands netstat, grep and if necessary awk. If Mosquitto is using port 1883 then the following will tell you what you want:
sudo netstat -n | grep :1883
sudo netstat -n | grep :1883
–
Odoacer No.
It might be better discussing this on the mosquitto mailing list: https://launchpad.net/~mqtt-users
well, I now created a workaround using a PHP script: it starts the mosquitto broker, reads the output, and if someone connects or disconnects it sends an XML string with the connected clients to the broker. (the posted code is a bit simplified as I additionally query a database for more information about the user)
<?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);
?>
A good work-around for this is to have the clients(if possible) define a Last will and testament(LWT). Your server will subscribe to a special topic where the LWT will be published to and assume all clients as online unless they publish to that topic.
You can get list of online/connected client from mosquitto.log file on server if you access it.
- Read last line that added to the log file and process it with regex to access to deviceID.
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);
}
}
});
- Translate with regex
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}`);
}
}
- Do the process
function processOnlineClient(deviceId){
console.log(`${deviceId} is Online`);
}
See this repo that I created 📦 msqtConnectedClinets in nodeJS.
© 2022 - 2024 — McMap. All rights reserved.