MQTT入门(三)

在上一篇中,我们使用了Mosquitto作为MQTT的Broker,MQTT.fx作为Client,Wireshark作为抓包工具分析了MQTT协议的内容

这篇仍然使用上述工具,着重分析MQTT的以下特性:

  • QoS
  • Will
  • Retain
  • Persistent Session

1 QoS

客户端可以在Sub/Pub时分别指定QoS(Quality of Service)说明delivery的服务质量

上一篇说过,注意Pub/Sub时指定的QoS是要区分开的:

  • Pub时指定的QoS,影响的是Publisher Client与Broker之间delivery的服务质量
  • Sub时指定的QoS,影响的是Subscriber Client与Broker之间delivery的服务质量
  • 一个规则就是QoS取Pub/Sub中较小的值

QoS的值可以是以下三个:

  • 0At most once,最多发一次消息
  • 1At lease once,至少发一次消息
  • 2Exactly once,就只发一次消息

QoS 0表示只发一次,不论对方是否收到,对方不用给响应,所以不需要Message Identifier来标识请求,而QoS 1,QoS 2都需要对方给出响应所以请求中带有Message Identifier

下面主要介绍下QoS 1和QoS 2的流程

1.1 QoS 1

MQTT.fx

Wireshark

注意DUP Flag

QoS 1:Client需要一直发送消息(自行实现),直到收到对应的Ack,如果Client没有收到Ack,会以同样的Message Identifier继续发送,所以同时订阅这个Topic的Subscriber可能会收到多条重复内容的消息,所以Subscriber需要根据Message Identifier自行去重(尽管DUP Flag已经为Set,这个和QoS一样分开考虑的)

1.2 QoS 2

MQTT.fx

Wireshark

如上可以看到包含了如下四步:

  • Publish Message:Publisher发布消息
  • Publish Received:Broker对收到Publisher的消息进行确认
  • Publish Release:Publisher知道了Broker收到了自己的消息,此时就可以Discard掉消息了
  • Publish Complete:通知Publisher,Broker收到了Publish Release消息,Publish过程完成了

为什么会要四步,简而言之就是需要双方的确认,而不像QoS 1那样单方面确认。==QoS 2 比较难理解==,我们逐步细化、分析4个子步骤过程步骤,以及如果失败,后续操作是什么(以Publish Client到Broker为例子)

1.2.1 Publish Message

这个就是正常的Publish Message附带有Message Identifier

1.2.2 Publish Received

Publish Message的响应,附带有对应的Message Identifier

如果Publisher没有收到Publish Received响应,则要重传Publish Message(因为没收到响应等同于Publish Message发送失败)

1.2.3 Publish Released

如果Publisher收到了Publish Received响应,则Publisher知道Broker收到了Message Identifier标识的数据,所以本地就可以Discard掉数据了,所以此时发送的是Publish Released

1.2.4 Publish Complete

Publish Released的响应,附带有对应的Message Identifier,说明Publish的过程结束了

如果Publisher没有收到Publish Complete响应,则要重传Publish Released(因为没收到响应等同于Publish Released发送失败,进而Publisher会认为Broker以为自己没有收到Publish Received

注意所有失败的后续操作都是由Publisher发起(因为Publisher是请求的发起发):

  • 重发Publish Message
  • 重发Publish Released

2 Will

这部分介绍MQTT遗嘱(Last Will and Testament)相关内容 当设备意外断开连接,则Broker会往指定topic发送遗嘱消息

注意遗嘱是针对ungraceful disconnection即意外的断开连接,比如电池因素、网路问题,而不是针对MQTT Disconnect

遗嘱是在Client Connect连接的时候指定的:
MQTT.fx

Wireshark

注意以下信息(在上一篇Connect部分的时候没有说):

  • Will Retain:Not set,Will的消息是否是Retian,这部分Retain会说
  • Will Flag:Set
  • QoS Level:指明Broker会将遗嘱会已什么QoS发给Subscriber,和Subscriber订阅是指明的QoS,两者取最小值
  • Will TopicWill Message:消息内容和topic

Will常和Retain搭配起来使用用来观测设备状态

3 Persistent Session

默认情况下Client和Broker之间的session是non-persistent的,即双方不会存储记录任何有关session的信息,下次Connect又是新的连接。

可以在Connect时设置Clean Session为Not Set,这样的连接会一直使用Broker上存储的有关特定Client ID的会话信息,这样直到下次Clean Session为Set

对于Persistent SessionBroker会存储如下信息:

  • 有关特定Client ID之前的Session是否存在,即在Connect时会返回Client是否使用了之前的Session,如下Session Present

  • Client订阅的topic
  • Client在离线期间没有收到的所有QoS 1 or 2消息
  • Client还没有确认的QoS 1 or Qos 2消息

对于Persistent SessionClient会存储如下信息:

  • Broker还没有确认的QoS 1 or QoS 2消息

如下在Client ID为zqq的Client离线期间,发布了许多消息:

如下当Client上线是,继续订阅之后仍然能收到之前错过的消息:

4 Retain

发布方是感知不到订阅方的存在的,发布的消息也只是给Broker,所以发布方没发确定订阅方是否在线、是否能收到消息,Retain基于此应运而生,让离线设备上线时能收到之前发布的消息

如下所示,MQTT.fx作为Publisher客户端,发布RetainSet的消息

在消息发布之后,mosquitto_sub作为另一个客户端订阅上述消息的topic,则仍然能收到数据 MQTT.fx

mosquitto_sub

Wireshark

注意:Subscriber收到的QoS取值是Publish时和Subscribe时的二者最低

5 Keep Alive

在Connect时可以指定Keep alive,用于确保Client和Broker之间仍然是连接状态

Keep alive的数值定义了允许客户端“休眠”的最大时间间隔,若在改该间隔1.5倍之后,Broker没有收到任何客户端的操作请求,则断开和该客户端的连接

所以终端可以定时发送Ping,用以保活,Ping请求中不需要Client ID,因为是解决TCP half open问题

6 参考

http://www.steves-internet-guide.com/understanding-mqtt-qos-levels-part-1/
https://www.hivemq.com/tags/mqtt-essentials/
mqtt essentials - a lightweight iot protocol

Tags:

Categories:

Updated: