EMQX 设备上下线监听

对于iot 来说,设备上的上下线事件非常关键并重要,怎对事件的监听呢?

在mqtt协议中,存在LTW(Last Will and Testament)遗言机制,该机制只能捕捉客户端异常离线的通知,而无法获取正常通过disconnect断开连接的通知。

LTW(Last Will and Testament)遗言机制
客户端在连接到Mqtt服务器时,需指定will topic和will message遗言信息,
之后若在客户端异常断开(弱网络、服务被终止,而非正常disconnet)时会由mqtt服务器主动向will topic发送will message,
此时其他监听will topic的用户即可获得客户端离线的will遗言通知;

而在Emqx,存在系统主题订阅,其中的系统主题

上线通知:

$SYS/brokers/${node}/clients/${clientId}/connected

下线通知

$SYS/brokers/${node}/clients/${clientId}/disconnected

LWT和Emqx SYS主题通知效果对比:

机制\事件 connect disconnect 异常disconnect
$SYS/brokers/${node}/clients/${clientId}/connected    
$SYS/brokers/${node}/clients/${clientId}/disconnected  
LWT    

通过实际测试对比发现,LWT仅支持异常disconnect的通知,而emqx的$SYS/brokers/${node}/clients/${clientId}/disconnected系统主题可以捕捉到所有离线通知(主动diconnect、异常disconnect),即emqx的系统主题即可完整支持客户端上线、下线监听的需求。可以根据实际的需求选择适当的机制。

emqx中使用上下线事件:

connected 事件消息的 Payload 解析成 JSON 格式如下:

{
    "username":"undefined",
    "ts":1582687922392,
    "sockport":1883,
    "proto_ver":5,
    "proto_name":"MQTT",
    "keepalive":300,
    "ipaddress":"127.0.0.1",
    "expiry_interval":0,
    "connected_at":1582687922,
    "connack":0,
    "clientid":"emqtt-8348fe27a87976ad4db3",
    "clean_start":true
}

disconnected 事件消息的 Payload 解析成 JSON 格式如下:

{
    "username":"undefined",
    "ts":1582688032203,
    "reason":"tcp_closed",
    "disconnected_at":1582688032,
    "clientid":"emqtt-8348fe27a87976ad4db3"
}

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

$SYS/brokers/+/clients/#

内置 ACL设置:

内置 ACL 通过文件设置规则,使用上足够简单轻量,适用于规则数量可预测、无变动需求或变动较小的项目。

ACL 规则文件:

etc/acl.conf

内置 ACL 优先级最低,可以被 ACL 插件覆盖,如需禁用全部注释即可。规则文件更改后需重启 EMQ X 以应用生效。

定义 ACL:

内置 ACL 是优先级最低规则表,在所有的 ACL 检查完成后,如果仍然未命中则检查默认的 ACL 规则。

该规则文件以 Erlang 语法的格式进行描述:

%% 允许 "dashboard" 用户 订阅 "$SYS/#" 主题
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.

%% 允许 IP 地址为 "127.0.0.1" 的用户 发布/订阅 "#SYS/#","#" 主题
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.

%% 拒绝 "所有用户" 订阅 "$SYS/#" "#" 主题
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.

%% 允许其它任意的发布订阅操作
{allow, all}.
  1. 第一条规则允许客户端发布订阅所有主题
  2. 第二条规则禁止全部客户端订阅 $SYS/# 与 # 主题
  3. 第三条规则允许 ip 地址为 127.0.0.1 的客户端发布/订阅 $SYS/# 与 # 主题,为第二条开了特例
  4. 第四条规则允许用户名为 dashboard 的客户端订阅 $SYS/# 主题,为第二条开了特例

可知,默认的 ACL 主要是为了限制客户端对系统主题 $SYS/# 和全通配主题 # 的权限。

如果想监听系统主题上下线,需要如下配置

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

重新加载acl文件(或者重启emqx服务)

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

$SYS/brokers/+/clients/#

这样比较方便,只不过需要我们在回调函数中进行Topic主题的区分就可以了,例如:

  /**
     * subscribe后得到的消息会执行到这里面
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String msg = new String(message.getPayload());
        try {
            JSONObject jsonObject = JSON.parseObject(msg);
            String clientId = String.valueOf(jsonObject.get("clientid"));
            if (topic.endsWith("disconnected")) {
                log.info("客户端已掉线:{}",clientId);
            } else {
                log.info("客户端已上线:{}",clientId);
            }
        } catch (JSONException e) {
            log.error("JSON Format Parsing Exception : {}", msg);
        }
    }

猜你喜欢

转载自blog.csdn.net/houxian1103/article/details/113147963