目录

  • 一、MQTT机制
  • 二、服务质量(QOS)
  • 三、保留消息(Retain)
  • 四、心跳机制(KeepAlive)
  • 五、MQTT遗嘱(Will)
  • 六、连接服务器(connect)
  • 七、相关资料

注明:资料参考自——太极创客

arduino中有一个用于连接MQTT服务器的库pubsubclient,该库官方API文档

一、MQTT机制

mqtt协议基于订阅和发布机制。

订阅:设备订阅某些主题。
 发布:设备向某些主题发布内容。

设备A订阅某些topic主题,如果有设备B向订阅的topic主题发送信息,那么设备A就可以收到所订阅主题的信息。topic主题就有点像微信的公众号。只不过他们之间是双向的。

mqtt subscribe python 多个topic mqtt的topic_qt


mqtt subscribe python 多个topic mqtt的topic_物联网_02

二、服务质量(QOS)

mqtt subscribe python 多个topic mqtt的topic_客户端_03

什么是服务质量?
一个物联网系统中有些信息非常重要,我们需要确保这类重要信息可以准确无误的发送和接收,而有些信息则相对不那么重要,这类信息如果在传输中丢失不会影响系统的运行。

MQTT服务质量(Quality of Service 缩写 QoS)正是用于告知物联网系统,哪些信息是重要信息需要准确无误的传输,而哪些信息不那么重要,即使丢失也没有问题。

MQTT协议有三种服务质量级别:

QoS = 0 – 最多发一次
QoS = 1 – 最少发一次
QoS = 2 – 保证收一次

以上三种不同的服务质量级别意味着不同的MQTT传输流程。对于较为重要的MQTT消息,我们通常会选择QoS>0的服务级别(即QoS 为1或2)。

QoS=1通讯时的注意事项:
如想在MQTT通讯中实现服务质量等级为1级(QoS=1),我们要分别对消息的发布端课接收端进行相应的设置。以下列表中的内容是具体需要采取的措施。

  • 接收端连接服务端时cleanSession设置为false
  • 接收端订阅主题时QoS=1
  • 发布端发布消息时QoS=1

QoS=2通讯时的注意事项
如想在MQTT通讯中实现服务质量等级为2级(QoS=2),我们要分别对消息的发布端和接收端进行相应的设置。以下列表中的内容是具体需要采取的措施。

  • 接收端连接服务端时cleanSession设置为false
  • 接收端订阅主题时QoS=2
  • 发布端发布消息时QoS=2

总结:

  • 若想实现QoS>0,订阅端连接服务端时cleanSession需要设置为false,订阅端订阅主题时QoS>0,发布端发布消息时的QoS>0。
  • 服务端会选择发布消息和订阅消息中较低的QoS来实现消息传输,这也被称作“服务降级”。
  • QoS = 0, 占用的网络资源最低,但是接收端可能会出现无法接收消息的情况,所以适用于传输重要性较低的信息。
  • QoS = 1, MQTT会确保接收端能够接收到消息,但是有可能出现接收端反复接收同一消息的情况。
  • QoS = 2, MQTT会确保接收端只接收到一次消息。但是QoS为2时消息传输最慢,另外消息传输需要多次确认,因此所占用的网络资源也是最多的。此类服务等级适用于重要消息传输。
  • 由于QoS1和QoS2都能确保客户端接收到消息,但是QoS1所占用的资源较QoS2占用资源更小。因此建议使用QoS1来实现网络资源较为珍贵的环境下传输重要信息。

三、保留消息(Retain)


保留消息的作用
要讲明“保留消息”这一概念,我们先看一个场景。假设我们正在利用MQTT协议开发一套智能家居物联网系统。在该系统中有一台专门用于检测和发布室温信息的MQTT客户端,它每到整点时就会测量当前室温并且向MQTT服务端发布室温测量结果。

假设在该智能家具物联网系统中,还有一台环境信息显示客户端。这台客户端的作用就是把当前的室温显示在屏幕上以便我们实时了解室内温度。换句话说,这台环境信息显示客户端一启动就会订阅室温主题,这样室温检测客户端一发布消息,显示客户端就能获取到最新的温度消息并显示在屏幕上了。

假设某天上午7:00,我们的室温检测客户端将最新的室温消息发布到了服务端,那么订阅了室温消息的显示客户端也就马上获取到室温消息并且显示在屏幕上。

然而在7:10的时候,家里的小狗不小心把显示客户端的电源碰掉了,显示客户端没有电也就自动关机了。我们发现这一问题后,马上把显示客户端重新通电,客户端通电启动后会立刻订阅室温主题。

但这时候问题出现了,室温测量客户端每到整点才发布一次温度信息。上一次发布时间是7:00,下一次发布时间是8:00。所以,尽管显示客户端订阅了室温主题,它还要等到8:00钟才能收到最新室温消息。在8:00前的几十分钟里,显示客户端无法获知当前室温信息,也就无法将室温信息显示在屏幕上供我们查阅。

为了避免以上情况出现,我们可以让室温测量客户端在每次向室温主题发布消息时都使用“保留消息”这一模式将温度信息发布到服务端。这样无论显示客户端在任何时间订阅室温主题,都会马上收到该主题中的“保留消息”,也就是温度测量客户端发布的最新室温消息。


解决的问题:使订阅某一主题的设备,能收到其他设备之前发给该主题的信息。

mqtt subscribe python 多个topic mqtt的topic_服务端_04


在发布保留消息时,MQTT设备需要将PUBLISH报文中retainFlag设置为true。当然,如果要发布非保留消息,那么PUBLISH报文中retainFlag设置为false。

  • 修改保留消息的方法

每一个主题只能有一个“保留消息”,如果客户端想要更新“保留消息”,就需要向该主题发送一条新的“保留消息”,这样服务端会将新的“保留消息”覆盖旧的“保留消息”。当有客户端订阅该主题时,服务端就会将最新的“保留消息”发送给订阅客户端了。

  • 删除保留消息的方法

如果要删除主题的“保留消息”,可以通过向该主题发布一条空的“保留消息”,也就是发送一条0字节payload的“保留消息”

四、心跳机制(KeepAlive)

mqtt subscribe python 多个topic mqtt的topic_服务端_05

服务端可以使用类似心跳检测的方法,来判断客户端是否在线。

让客户端在没有向服务端发送信息时,可以定时向服务端发送一条消息。这条用于心跳机制的消息也被称作心跳请求(PINGREQ)。心跳请求的作用正是用于告知服务端,当前客户端依然在线。服务端在收到客户端的心跳请求后,会回复一条消息。这条回复消息被称作心跳响应(PINGRESP)。

另外,心跳机制不仅仅用于服务端判断客户端是否在线。客户端也可以利用这一机制来判断自己是否与服务端仍保持连接。如果客户端发送了心跳请求(PINGREQ)给服务端一段时间后,仍然没有收到服务端回复的心跳确认。那么客户端也会认为自己已经断开了与服务端的连接。

五、MQTT遗嘱(Will)

mqtt subscribe python 多个topic mqtt的topic_客户端_06

MQTT协议允许客户端在“活着”的时候就写好遗嘱,这样一旦客户端意外断线,服务端就可以将客户端的遗嘱公之于众。

客户端的遗嘱只在意外断线时才会发布,如果客户端正常的断开了与服务端的连接,这个遗嘱机制是不会启动的,服务端也不会将客户端的遗嘱公布。

mqtt subscribe python 多个topic mqtt的topic_qt_07


MQTT遗嘱操作建议

在使用MQTT遗嘱时,我们建议您通过以下方法让设备的MQTT遗嘱机制可以更好的发挥作用。

假设我们现在有一台MQTT客户端。它的client id是 client-1。它的遗嘱主题是“client-1-will”

  1. 当client-1连接服务端时,CONNECT报文中的遗嘱消息是“offline”。并且它的遗嘱保留设置为true。
  2. 当client-1成功连接服务端后,立即向遗嘱主题“client-1-will”发布一条消息“online”。同时在发布此消息时,保留标志设置为true。这样,只要client-1在线,那么任何设备一订阅“client-1-will”就能收到设备在线的消息“online”。
  3. 如果client-1发生意外离线。那么任何设备一订阅“client-1-will”就会收到设备离线的消息”offline”。
  4. 如果client-1恢复连接,那么它会将遗嘱主题“client-1-will”的保留消息更改为“online”,这样任何设备一订阅“client-1-will”就能收到设备在线的消息“online”。

即可以通过合理使用遗嘱,实现实时监控设备在线状态。

六、连接服务器(connect)

mqtt subscribe python 多个topic mqtt的topic_客户端_08


cleanSession – 清除会话

MQTT通讯中有些客户端必须准确无误的收到报文,有些则不需要。

为了保证重要的MQTT报文可以被客户端准确无误的收到。在服务端向客户端发送报文后,客户端会向服务端返回一个确认报文。如果服务端没有收到客户端返回的确认报文,那么服务端就会认为刚刚发送给客户端的报文没有被准确无误的送达。在这种情况下,服务端将会执行以下两个操作:

  • 操作1:将尚未被客户端确认的报文保存起来
  • 操作2:再次尝试向客户端发送报文,并且再次等待客户端发来确认信息。

如果cleanSession 被设置为“true”。那么服务端不需要客户端确认收到报文,也不会保存任何报文。在这种情况下,即使客户端错过了服务端发来的报文,也没办法让服务端再次发送报文。

如果cleanSession 被设置为“true”。那么服务端不需要客户端确认收到报文,也不会保存任何报文。在这种情况下,即使客户端错过了服务端发来的报文,也没办法让服务端再次发送报文

请注意,如果需要服务端保存重要报文,光设置cleanSession 为false是不够的,还需要传递的MQTT信息QoS级别大于0。