本文基于标准MQTT讨论,不适合其他对MQTT机制做了修改的非标准MQTT协议。

 

MQTT设计了一套保证消息稳定传输的机制,包括消息应答、存储和重传。在这套机制下,提供了三种不同层次QoS(Quality of Service):

  • QoS0,发送就不管了,最多一次;
  • QoS1,发送之后依赖MQTT规范,是否启动重传消息,所以至少一次;
  • QoS2,发送之后依赖MQTT消息机制,确保只有一次。

QoS 是消息的发送方(Sender)和接受方(Receiver)之间达成的一个协议:(MQTT不是端到端的通信)

  1. QoS0 代表,Sender 发送的一条消息,Receiver 最多能收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,也就算了;这是完全依赖TCP重传机制,如果网络不好,TCP的重传也不是100%可靠,加上MQTT是Publisher 发出去的消息是依赖代理服务器完成转发,所以消息最多一次。
  2. QoS1 代表,Sender 发送的一条消息,Receiver 至少能收到一次,也就是说 Sender 向 Receiver 发送消息,如果发送之后没有收到对应的PUBACK,就会继续重试,直到发送者Sender 接收到 Receiver 发送的 PUBACK 为止,因为重传的原因,Receiver 有可能会收到重复的消息;
  3. QoS2 代表,Sender 发送的一条消息,Receiver 确保能收到而且只收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。(个人理解这一点有点像TCP三次握手的交互过程)

下面讨论Qos不降级的情况,即订阅者与发布者的Qos等级相同。

 

Qos 0的交互流程:

slrum qos参数详解 sqm qos是什么_代理服务器

 

  1. 消息的分发依赖于底层网络的能力。接收者不会发送响应,发送者也不会重试。消息可能送达一次也可能根本没送达。消息从Publisher发送给代理服务broker,或者broker发送给Subscriher,都可能会丢失。

注意:对于QoS 0的消息, DUP标志必须设置为0 

 

Qos 1的交互流程:

slrum qos参数详解 sqm qos是什么_标识符_02

 

只有当QoS等级是1或2时, 报文标识符( Packet Identifier) 字段才能出现在PUBLISH报文中。下面是MQTT Qos的补充说明:

[MQTT-4.3.2-1] 对于QoS 1的分发协议, 发送者

  • 每次发送新的应用消息都必须分配一个未使用的报文标识符。
  • MUST send a PUBLISH Packet containing this Packet Identifier with QoS=1,DUP=0。
  • 发送的PUBLISH报文必须包含报文标识符且QoS等于1,DUP等于0。
  • 必须将这个PUBLISH报文看作是 未确认的 , 直到从接收者那收到对应的PUBACK报文。 4.4节有一个关于未确认消息的讨论。

[MQTT-4.3.2-2] 对于QoS 1的分发协议, 接收者

  • 响应的PUBACK报文必须包含一个报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。
  • 发送了PUBACK报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH报文,当作一个新的消息, 并忽略它的DUP标志的值。
  1. Sender 向 Receiver 发送一个带有消息数据的 PUBLISH 包, 并在本地保存这个 PUBLISH 包。
  2. Receiver 收到 PUBLISH 包以后,向 Sender 发送一个 PUBACK 数据包,PUBACK 数据包没有消息体(Payload),在可变头中(Variable header)中有一个包标识(Packet Identifier),和它收到的 PUBLISH 包中的报文标识符(Packet Identifier) 一致。
  3. Sender 收到 PUBACK 之后,根据 PUBACK 包中的 Packet Identifier 找到本地保存的 PUBLISH 包,然后丢弃掉,一次消息的发送完成。
  4. 如果 Sender 在一段时间内没有收到 PUBLISH 包对应的 PUBACK,它将该 PUBLISH 包的 DUP 标识设为 1(代表是重新发送的 PUBLISH 包),然后重新发送该 PUBLISH 包。重复这个流程,直到收到 PUBACK,然后执行第 3 步。

注意:Qos 1代理服务器是不会进行去重的,只要发布者或者代理服务器没有收到PUBACK,就认为主题消息没有发送成功进入重发,代理服务器或者订阅者,不会根据dup的值进行去重。

        换句话说,代理服务器(broker)或者订阅者(Subscriber)在发送PUBACK报文时,(Publisher 者)发布消息主题的程序或者代理服务器(broker)的程序,已经对PUBACK报文做了判断,那么还是会重发该主题消息,并且dup标志位会+1,这样订阅者或者代理服务器就会收到多份重复的消息。并且不会去重!

 

Qos 2的交互流程:

slrum qos参数详解 sqm qos是什么_代理服务器_03

 

只有当QoS等级是1或2时, 报文标识符( Packet Identifier) 字段才能出现在PUBLISH报文中,另外QoS 2在消息头有Message ID。下面是补充说明

[MQTT-4.3.3-1] 对于QoS 2的分发协议, 发送者

1、必须给要发送的新应用消息分配一个未使用的报文标识符。

  • MUST send a PUBLISH packet containing this Packet Identifier with QoS=2,DUP=0。

2、发送的PUBLISH报文必须包含报文标识符且报文的QoS等于2,DUP等于0。

  • 必须将这个PUBLISH报文看作是 未确认的 , 直到从接收者那收到对应的PUBREC报文。 4.4节有一个关于未确认消息的讨论。
  • 收到PUBREC报文后必须发送一个PUBREL报文。 PUBREL报文必须包含与原始PUBLISH报文相同的报文标识符。
  • 必须将这个PUBREL报文看作是 未确认的 , 直到从接收者那收到对应的PUBCOMP报文。
  • 一旦发送了对应的PUBREL报文就不能重发这个PUBLISH报文。

[MQTT-4.3.3-2] 对于QoS 2的分发协议, 接收者

  • 响应的PUBREC报文必须包含报文标识符, 这个标识符来自接收到的、 已经接受所有权的PUBLISH报文。
  • 在收到对应的PUBREL报文之前, 接收者必须发送PUBREC报文确认任何后续的具有相同标识符的PUBLISH报文。 在这种情况下, 它不能重复分发消息给任何后续的接收者。
  • 响应PUBREL报文的PUBCOMP报文必须包含与PUBREL报文相同的标识符。

        发送PUBCOMP报文之后, 接收者必须将包含相同报文标识符的任何后续PUBLISH报文当作一个新的发布。

  1. Sender 发送 QoS 为 2 的 PUBLISH 数据包,数据包包含报文标识符:Packet Identifier ,并在本地保存该 PUBLISH 包;
  2. Receiver (代理服务器或者订阅者)收到 PUBLISH 数据包以后,在本地保存 PUBLISH 包,并回复 Sender 一个 PUBREC 数据包,PUBREC 数据包可变头中的 报文标识符(Packet Identifier) 与 Sender 发送的报文标识符(Packet Identifier)一致,但是没有消息体(Payload);
  3. 当 Sender 收到 PUBREC,它就可以安全地丢弃掉初始发送的PUBLISH包,同时保存该 PUBREC 数据包,同时回复 Receiver 一个 PUBREL 数据包,PUBREL 数据包可变头中的报文标识符(Packet Identifier)保持不变,同样没有消息体(Payload);
  4. 如果 Sender 在一定时间内没有收到 PUBREC,它会把 PUBLISH 包的重发标志位 DUP 标识设为 1,重新发送该 PUBLISH 数据包(Payload);(在第三步和第四步之间是可能存在消息重传的)
  5. 当 Receiver 收到 PUBREL 数据包,它可以丢弃掉保存的 PUBLISH 包,并回复 Sender 一个 PUBCOMP 数据包,PUBCOMP 数据包可变头中的报文标识符(Packet Identifier)保持不变,没有消息体(Payload);
  6. 当 Sender 收到 PUBCOMP 包,那么它认为数据包传输已完成,它会丢弃掉对应的 PUBREC 包。如果 Sender 在一定时间内没有收到 PUBCOMP 包,它会重新发送 PUBREL 数据包。

注意:

  1. 1.Qos 2代理服务器是不会进行去重的,只要发布者或者代理服务器,没有收到PUBREC,就认为主题消息没有发送成功进入重发,代理服务器或者订阅者,不会根据dup的值进行去重。这一步会有去重,保证收到主题消息的唯一性。
  2. 发送者或者代理服务器,收到PUBREC,就认为主题消息已经发送出去,不会进行重复发送;至于订阅者,MQTT会控制显示消息,如果收到了PUBREL就认为消息已经收到,只需要在发送PUBCOMP,完成MQTT Qos 2 的交互流程。

总结:

在Qos 1 情况下,如果PUBACK超时或者发送失败,就会重传消息;

在Qos 2情况下,在没有收到PUBREC之前,也是有消息重传的可能,但是在接收到PUBREC报文之后,主题消息被删除,这样就不会对下面的交互过程产生干扰,消息在这一步之后,只能重传PUBREC、PUBREL报文。