mqtt emqx 上下线监听

一、业务场景

好多朋友在咨询如何得知(监测)MQTT客户端状态(在线、离线),或者可以说是监测采集器状态。

其实这个在MQTT协议中已经给出系统主题,MQTT服务端可以知道客户端的任何情况,比如:什么时候上线和下线。

二、解决方案

$SYS/brokers/${node}/clients/${clientid}/connected:上线事件。当某客户端上线时,会向该主题(Topic)发布消息

 $SYS/brokers/${node}/clients/${clientid}/disconnected:掉线事件。当某客户端掉线时,会向该主题(Topic)发布消息

当然在开发的时候我们订阅两个主题比较麻烦,在这里我们可以采用主题通配符模式直接订阅一个主题即可:

$SYS/brokers/+/clients/#

 private void initMonitor() {
        String subTopic = "$SYS/brokers/+/clients/#";
        String clientId = "monitor_mqtt_emqx"+new Date().getTime();
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            MqttClient client = new MqttClient(broker, clientId, persistence);

            // MQTT 连接选项
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setUserName("admin");
            connOpts.setPassword("123456".toCharArray());
            // 保留会话
            //connOpts.setCleanSession(true);
            //设置重连
            connOpts.setAutomaticReconnect(true);

            // 设置回调
            client.setCallback(new OnMonitorCallback());

            // 建立连接
            System.out.println("monitor_Connecting to broker: " + broker);
            client.connect(connOpts);

            System.out.println("monitor_Connected");
            //System.out.println("Publishing message: " + content);

            // 订阅
            client.subscribe(subTopic);
        } catch (MqttException me) {
            System.out.println("monitor_reason " + me.getReasonCode());
            System.out.println("monitor_msg " + me.getMessage());
            System.out.println("monitor_loc " + me.getLocalizedMessage());
            System.out.println("monitor_cause " + me.getCause());
            System.out.println("monitor_excep " + me);
            me.printStackTrace();
        }
    }

public class OnMonitorCallback implements MqttCallback {
    public void connectionLost(Throwable cause) {
        // 连接丢失后,一般在这里面进行重连
        System.out.println("连接断开,可以做重连");
    }

    public void messageArrived(String topic, MqttMessage message) throws Exception {
         String msg = new String(message.getPayload());
         try {
             
             String result = new String(message.getPayload());
             Map resultMap2 = JsonUtil.jsonToMap(result);
             
             String clientId = String.valueOf(resultMap2.get("clientid"));
             if (topic.endsWith("disconnected")) {
                 System.out.println("客户端已掉线:"+clientId);
             } else {
                 System.out.println("客户端已上线:"+clientId);
             }
         } catch (JSONException e) {
             System.out.println("monitor_JSON Format Parsing Exception : "+msg);
         }
    }

    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("deliveryComplete---------" + token.isComplete());
    }
}

三、修改配置文件

修改etc/acl.conf 如果担心其他人非法获取离线消息,可以设置订阅权限
设置allow所有用户订阅$SYS/brokers/+/clients/#主题
 

{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.

{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.

{allow, all, subscribe, ["$SYS/brokers/+/clients/#"]}.

{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.

{allow, all}.

你可能感兴趣的:(java,开发语言)