Retained消息

Retained消息

让我们来假设一个场景:你有一个温度传感器,它每三个小时向一个Topic发布当前的温度。那么问题来了,有一个新的订阅者在它刚刚发布了当前温度之后订阅了这个主题,那么这个订阅端什么时候能才能收到温度消息?对的,它必须等到三个小时以后,温度传感器再次发布消息的时候才能收到。在这之前,这个新的订阅者对传感器的温度数据一无所知。

这个时候就轮到Retained消息出场解决这个问题了。Retained消息是指在PUBLISH数据包中Retain标识设为1的消息,Broker收到这样的PUBLISH包以后,将保存这个消息,当有一个新的订阅者订阅相应主题的时候,Broker会马上将这个消息发送给订阅者。

Retain消息有以下一些特点:

  • 一个Topic只能有1Retained消息,发布新的Retained消息将覆盖老的Retained消息;
  • 如果订阅者使用通配符订阅主题,它会收到所有匹配的主题上的Retained消息;
  • 只有新的订阅者才会收到Retained消息,如果订阅者重复订阅一个主题,也会被当做新的订阅者,然后收到Retained消息;
  • Retained消息发送到订阅者时,消息的Retain标识仍然是1,订阅者可以判断这个消息是否是Retained消息,以做相应的处理。

注意:Retained消息和持久性会话没有任何关系,Retained消息是Broker为每一个Topic单独存储的,而持久性会话是Broker为每一个Client单独存储的。如果你想删除一个Retained消息也很简单,只要向这个主题发布一个Payload长度为0Retained消息就可以了。

LWT(最后遗嘱)

LWT全称为Last Will and Testament,也就是我们在连接到Broker时提到的遗嘱,包括遗嘱主题、遗嘱QoS、遗嘱消息等。顾名思义,当Broker检测到Client非正常地断开连接的时候,就会向遗嘱主题里面发布一条消息。遗嘱相关的设置是在建立连接的时候,在CONNECT数据包里面的Variable header(可变头与) Payload(有效载荷)中指定的。

  • Will Flag:是10使用LWT
  • Will Topic:遗嘱主题名,不可使用通配符(在CONNECT报文中的 有效载荷 中 设置)
  • Will Qos:发布遗嘱消息时使用的QoS等级,如果遗嘱标志(Will Flag)被设置为0,遗嘱QoS也必须设置为0(0x00)
  • Will Retain:遗嘱消息的Retain标识
  • Will Message:遗嘱消息内容(在CONNECT报文中的有效载荷中设置)

Broker在以下情况下认为Client是非正常断开连接的:

  • Broker检测到底层的I/O异常;
  • Client未能在Keep Alive的间隔内和Broker之间有消息交互;
  • Client在关闭底层TCP连接前没有发送DISCONNECT数据包;
  • Broker因为协议错误关闭和Client的连接,比如Client发送了一个格式错误的MQTT数据包。

如果Client通过发布DISCONNECT数据包断开连接,这个属于正常断开连接,不会触发LWT的机制,同时,Broker还会丢弃掉这个Client在连接时指定的LWT参数。根据遗嘱的属性和触发机制,我们不难看出,遗嘱常用于获取设备的连接状态。

注意,设置好遗嘱以后还不够(因为你只要订阅者一启动就会收到遗嘱消息,如果此时发布者已经在线,会导致不准确,所以,还需要在设备成功连接MQTT的时候主动发个消息,发送的主题必须和遗嘱的主题相同,设置好消息的retain属性,让其自动纠正过来。