MQTT EMQX中如何监听客户端上下线?并在业务中正常使用

MQTT EMQX中如何监听客户端上下线?

最近自助洗车项目改用了全新的客户端通讯方案MQTT,发现了一些问题。

之前使用Websocket方式,服务端在发送入场开门命令的时候如果try catch到错误,认为门店电路或网络出现问题,就不会生成订单。而改用MQTT后,开门指令是发送给EMQX服务端,只能检测到在发送这一层不出现问题,而如果客户端没有订阅服务端主题的情况下,并不能接收开门指令,会造成的现象就是:订单生成了,门却没开。遂有了以下的解决方案。

ps:本文重在解决思路,而非代码。如果尚未接触过EMQX,可能会影响您的观看。

最初方案1:$SYS 系统主题

提示

EMQX 默认只允许本机的 MQTT 客户端订阅 $SYS 主题,请参照 内置 ACL 修改发布订阅 ACL 规则。

监听客户端上下线事件

$SYS` 主题前缀: `$SYS/brokers/${node}/clients/
主题 (Topic)说明
${clientid}/connected上线事件。当任意客户端上线时,EMQX 就会发布该主题的消息
${clientid}/disconnected下线事件。当任意客户端下线时,EMQX 就会发布该主题的消息

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

{
    "username": "foo",
    "ts": 1625572213873,
    "sockport": 1883,
    "proto_ver": 4,
    "proto_name": "MQTT",
    "keepalive": 60,
    "ipaddress": "127.0.0.1",
    "expiry_interval": 0,
    "connected_at": 1625572213873,
    "connack": 0,
    "clientid": "emqtt-8348fe27a87976ad4db3",
    "clean_start": true
}

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

{
    "username": "foo",
    "ts": 1625572213873,
    "sockport": 1883,
    "reason": "tcp_closed",
    "proto_ver": 4,
    "proto_name": "MQTT",
    "ipaddress": "127.0.0.1",
    "disconnected_at": 1625572213873,
    "clientid": "emqtt-8348fe27a87976ad4db3"
}

思路:
  1. 订阅主题 S Y S / b r o k e r s / SYS/brokers/ SYS/brokers/{node}/clients/${clientid}/(connected/disconnected)
  2. 订阅后客户端上下线均会发送上下线信息,然后在接收消息端处理业务逻辑即可。
缺点:
  1. 该方案因为是订阅主题,如果emqx服务崩溃导致重连后,因为订阅该主题的本身需要重连,而在重连期间或许其他客户端已经连接而没能收到主题消息(这里有点绕),导致并不一定能接收到topic,可靠性很差。
  2. 实际生成中没法使用,而且官方也不推荐这种方式。当时想着这样的方式简单,最后实验结果是根本没法使用。

最终解决方案:WebHook

WebHook 是由 emqx_web_hook (opens new window)插件提供的 将 EMQX 中的钩子事件通知到某个 Web 服务 的功能。

WebHook 的内部实现是基于 钩子,但它更靠近顶层一些。它通过在钩子上的挂载回调函数,获取到 EMQX 中的各种事件,并转发至 emqx_web_hook 中配置的 Web 服务器。

WebHook 对于事件的处理是单向的,它仅支持将 EMQX 中的事件推送给 Web 服务,并不关心 Web 服务的返回。 借助 Webhook 可以完成设备在线、上下线记录,订阅与消息存储、消息送达确认等诸多业务。

总结就是,当客户端上线后,给指定的web地址发送一条信息。

如何使用
  1. Webhook 的配置文件位于 etc/plugins/emqx_web_hook.conf,配置项的详细说明可以查看 配置项。这个配置非常简单,打开指定文件后,官方已经写好这些了,只需要修改web.hook.url,和在你需要的钩子事件前的#号去掉即可。

web.hook.url = http://127.0.0.1:8080/webhook

web.hook.rule.client.connected.1     = {"action": "on_client_connected"}
web.hook.rule.client.disconnected.1  = {"action": "on_client_disconnected"}
#web.hook.rule.client.connect.1       = {"action": "on_client_connect"}
#web.hook.rule.client.connack.1       = {"action": "on_client_connack"}
#web.hook.rule.client.subscribe.1     = {"action": "on_client_subscribe"}
#web.hook.rule.client.unsubscribe.1   = {"action": "on_client_unsubscribe"}
web.hook.rule.session.subscribed.1   = {"action": "on_session_subscribed"}
web.hook.rule.session.unsubscribed.1 = {"action": "on_session_unsubscribed"}
#web.hook.rule.session.terminated.1   = {"action": "on_session_terminated"}
#web.hook.rule.message.publish.1      = {"action": "on_message_publish"}
#web.hook.rule.message.delivered.1    = {"action": "on_message_delivered"}
#web.hook.rule.message.acked.1        = {"action": "on_message_acked"}


  1. emqx 启用插件 webhook插件(emqx有web控制台,在插件里启用就可以)
  2. 然后就是自行搭建一个web服务,当客户端有指定事件后会主动推送。
优点:
  1. 该方案只要web服务端不崩溃,就一定会收到上下线事件,可靠性有保障。
  2. 耦合性更低。
改进:
  1. 该方案我没发现如何加密通讯,所以如果web服务对外暴露,小黑可以模拟发送一些数据,导致业务错乱。我的方案是在web端限制访问ip为emqx的服务端访问。
  2. 该方案可做为设备在线/不在线状态的辅助,更新到数据库。定时监测不在线状态事件大于指定时间的即告警通知人工处理,目前我的方案是离线15分钟会发送信息到公众号。
  3. 为什么说该方案作为辅助。本来打算该方案作为最终方案的,后来发现还有一个可靠性更高的,所以该方案就作为辅助了。可靠性更高的就是Emqx提供的 HTTP API ,在每次发送命令前调用检查,就能确认机器是否在线,该方案下次分享了。

如果本文对您有帮助,就点个star鼓励下吧~

想要探讨/摸鱼的小伙伴也可加我 157239486

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在MicroPython使用TLS单向认证连接MQTT服务器并发送消息需要使用到umqtt.simple库。 首先需要在本地创建证书文件(如ca.pem)。然后使用umqtt.simple.MQTTClient类创建MQTT客户端对象,并设置连接参数,如服务器地址、端口、客户端ID、证书文件路径等。 在连接时使用.set_ssl()函数设置TLS,并将ca.pem文件传入。 最后使用.connect()函数连接服务器,并使用.publish()函数发布消息。 例如: ```python from umqtt.simple import MQTTClient client = MQTTClient("my_client_id", "mqtt.example.com", port=8883) client.set_ssl("ca.pem") client.connect() client.publish("topic", "message") ``` 需要注意的是,如果使用的是micropython, 需要使用umqtt.robust库,并且在使用的时候需要把证书文件内容转成字符串传入。 ```python from umqtt.robust import MQTTClient import ubinascii # 读取证书文件 with open('ca.pem', 'r') as f: ca = f.read() client = MQTTClient(client_id, server, port=8883, user=None, password=None, ssl=True, ssl_params={'ca_certs':ca,'cert_reqs':ssl.CERT_REQUIRED}) client.connect() client.publish("topic", "message") ``` ### 回答2: 在Micropython,要使用TLS单向认证(客户端验证服务器)连接MQTT服务器并发送消息,需要遵循以下步骤: 1. 导入必要的库:首先,需要导入`network`和`ussl`库,`network`用于网络连接,`ussl`用于TLS连接。 2. 建立网络连接:使用`network`库建立与MQTT服务器的网络连接。可以使用`WLAN`或`LAN`类,具体方法取决于设备和网络类型。 3. 创建TLS连接:通过使用`ussl.wrap_socket`方法,创建TLS连接。使用此方法,需要提供已建立的网络连接和TLS协议的版本(如`ussl.PROTOCOL_TLSv1_2`)。 4. 连接MQTT服务器:使用`usocket`库的套接字方法,建立与MQTT服务器的连接。需要提供服务器的主机名和端口号。 5. 发送连接请求:使用MQTT协议的相关方法,发送连接请求给服务器。需要提供客户端ID、用户名、密码等信息。 6. 发布消息:使用MQTT协议的相关方法,向服务器发布消息。需要提供主题、消息内容和QoS等信息。 以下是一个示例代码: ```python import network import ussl import usocket import ubinascii from umqtt.simple import MQTTClient # 1. 导入必要的库 # 2. 建立网络连接 # 3. 创建TLS连接 sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM) sock = ussl.wrap_socket(sock, server_hostname="mqtt.example.com") # 4. 连接MQTT服务器 mqtt_client = MQTTClient("client_id", "mqtt.example.com", ssl_sock=sock) # 5. 发送连接请求 mqtt_client.connect() # 6. 发布消息 mqtt_client.publish("topic", "message") # 关闭连接 mqtt_client.disconnect() sock.close() ``` 以上示例代码用于连接名为"mqtt.example.com"的MQTT服务器,并向主题"topic"发布消息"message"。请根据实际情况修改主机名、端口号、客户端ID、用户名、密码、主题和消息内容等参数。 ### 回答3: 在Micropython使用TLS单向认证连接MQTT服务器并发送消息需要按照以下步骤进行: 1. 首先,确保您的Micropython设备以及MQTT服务器支持TLS协议。如果不支持,需要升级或更换设备和服务器。 2. 获取MQTT服务器的根证书(CA证书)以及客户端的证书和私钥。在确认服务器支持TLS时,可以向服务器管理员申请根证书,并从服务器获得客户端证书和私钥。 3. 将根证书、客户端证书和私钥文件分别保存到Micropython设备的文件系统,以便后续使用。 4. 在Micropython设备上使用TLS单向认证时,需要安装TLS支持库。可以通过安装`umqtt.robust`库来实现MQTT协议的通信,并安装`urequests`库来支持HTTPS协议,用于下载证书文件。 5. 设定MQTT服务器的连接参数,包括服务器的地址、端口号和MQTT客户端的ID。 6. 配置TLS客户端的参数,包括根证书文件路径、客户端证书和私钥文件路径等。 7. 在Micropython,可以使用`import socket`和`import ssl`模块来实现TLS连接。使用`socket`模块创建一个socket对象,然后使用`ssl.wrap_socket()`方法将其包装为TLS连接。 8. 使用MQTT的连接请求消息来连接MQTT服务器。 9. 连接成功后,可以使用MQTT的发布消息来发送消息到服务器。 以上是在Micropython使用TLS单向认证连接MQTT服务器并发送消息的大致步骤。具体实现过程可能因设备、服务器和框架版本而有所不同,因此需要根据具体情况进行调整。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值