mqtt 协议中的 QoS等级介绍

硅谷探秘者 mqtt协议 42 0 0

一、QoS等级

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

  • QoS0,At most once,至多一次;
  • QoS1,At least once,至少一次;
  • QoS2,Exactly once,确保只有一次;

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

  • QoS0 代表,Sender 发送的一条消息,Receiver 最多能收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,也就算了;
  • QoS1 代表,Sender 发送的一条消息,Receiver 至少能收到一次,也就是说 Sender 向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,但是因为重传的原因,Receiver 有可能会收到重复的消息;
  • QoS2 代表,Sender 发送的一条消息,Receiver 确保能收到而且只收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。

注意:
QoS是Sender和Receiver之间的协议,而不是Publisher和Subscriber之间的协议。换句话说,Publisher发布了一条QoS1的消息,只能保证Broker能至少收到一次这个消息;而对于Subscriber能否至少收到一次这个消息,还要取决于Subscriber在Subscibe的时候和Broker协商的QoS等级。

二、QoS0

  QoS0等级下,Sender和Receiver之间一次消息的传递流程如下:

  Sender向Receiver发送一个包含消息数据的PUBLISH包,然后不管结果如何,丢掉已发送的PUBLISH包,一条消息的发送完成。

三、QoS1

  QoS1要保证消息至少到达一次,所以有一个应答的机制。Sender和Receiver的一次消息的传递流程如下:

  • Sender向Receiver发送一个带有数据的PUBLISH包,并在本地保存这个PUBLISH包;
  • Receiver收到PUBLISH包以后,向Sender发送一个PUBACK数据包,PUBACK数据包没有消息体(Payload),在可变头中有一个包标识(Packet Identifier),和它收到的PUBLISH包中的Packet Identifier一致。
  • Sender收到PUBACK之后,根据PUBACK包中的Packet Identifier找到本地保存的PUBLISH包,然后丢弃掉,一次消息的发送完成。

但是消息传递流程中可能会出现问题:

  • 如果Sender在一段时间内没有收到PUBLISH包对应的PUBACK,它将该PUBLISH包的DUP标识设为1(代表是重新发送的PUBLISH包),然后重新发送该PUBLISH包。
  • Receiver可能会重复收到消息,需自行去重。

四、QoS2

  相比QoS0和QoS1,QoS2不仅要确保Receiver能收到Sender发送的消息,还需要确保消息不重复。它的重传和应答机制就要复杂一些,同时开销也是最大的。QoS2下,一次消息的传递流程如下所示:

  • Sender发送QoS为2的PUBLISH数据包,数据包 Packet Identifier 为 P,并在本地保存该PUBLISH包;
  • Receiver收到PUBLISH数据包后,在本地保存PUBLISH包的Packet Identifier P,并回复Sender一个PUBREC数据包,PUBREC数据包可变头中的Packet Identifier为P,没有消息体(Payload);
  • 当Sender收到PUBREC,它就可以安全的丢弃掉初始Packet Identifier为P的PUBLISH数据包。同时保存该PUBREC数据包,并回复Receiver一个PUBREL数据包,PUBREL数据包可变头中的Packet Identifier为P,没有消息体;
  • 当Receiver收到PUBREL数据包,它可以丢掉保存的PUBLISH包的Packet Identifier P,并回复Sender一个可变头中 Packet Identifier 为 P,没有消息体(Payload)的PUBCOMP数据包;
  • 当Sender收到PUBCOMP包,那么认为传输已完成,则丢掉对应的PUBREC数据包;

上面是一次完整无误的传输过程,然而传输过程中可能会出现以下情况:

  • 情况1:Sender发送PUBLISH数据包给Receiver的时候,发送失败;
  • 情况2:Sender已经成功发送PUBLISH数据包给Receiver了,但是Receiver发送PUBREC数据包失败;
  • 情况3:Sender已经成功收到了PUBREC数据包,但是PUBREL数据包发送失败;
  • 情况4:Receiver已经收到了PUBREL数据包,但是发送PUBCOMP数据包时发送失败

针对上述的问题,较为详细的处理方法如下:

  • 不管是情况1还是情况2,因为Sender在一定时间内没有收到PUBREC,那么它会把PUBLISH包的DUP标识设为1,重新发送该PUBLISH数据包;
  • 不管是情况3还是情况4,因为Sender在一定时间内没有收到PUBCOMP包,那么它会重新发送PUBREL数据包;
  • 针对情况2,Receiver可能会收到多个重复的PUBLISH包,更加完善的处理如下:
    Receiver在收到PUBLISH数据包之后,马上回复一个PUBREC数据包。并会在本地保存PUBLISH包的Packet Identifier P,不管之后因为重传多少次这个Packet Identifier 为P的数据包,Receiver都认为是重复的,丢弃。同时Receiver接收到QoS为2的PUBLISH数据包后,并不马上投递给上层,而是在本地做持久化,将消息保存起来(这里需要是持久化而不是保存在内存)。
  • 针对情况4,更加完善的处理如下:
    Receiver收到PUBREL数据包后,正式将消息递交给上层应用层,投递之后销毁Packet Identifier P,并发送PUBCOMP数据包,销毁之前的持久化消息。之后不管接收到多少个PUBREL数据包,因为没有Packet Identifier P,直接回复PUBCOMP数据包即可。
猜你喜欢
mqtt协议 27 /订阅(publish/subscribe)模式”轻量”通讯,该构建于TCP/IP上,由IBM在1999年发布。MQTT最大优点在于,可以以极少代码和有限带宽,为连接远程设备提供实
mqtt协议 35 名称长度,即’MQTT’为4字节长度。byte7表示别,此处固定为0x04。(表示v3.1.1)byte8表示连接标志,用1、0表示是否开启。第0位为保留位,固定为0.第1位为会话清理标志,1
official 93 什么是网络?网络就是为计算机网络进行数据交换而建立规则、标准或约定集合。有了网络才能实现不同设备、不同操作系统、不同软件之间数据交换。我们常说tcp和udp其实是操作系
mqtt协议 51 mqtt报文解析,参考:http://www.jiajiajia.club/blog/artical/kdv1qvpfgbh4/514  根据mqtt定义,剩余长度字段是可变,最少用一个
weblog 251 1.修改配置文件修改activemq安装目录下./bin目录下配置文件activemq.xml在transportConnectors标签添加nio
official 106 Websocket和http关系websocket是基于TCP一个应用,与HTTP关联之处在于websocket握手数据被HTTP服务器当作HTTP包来处理,主要通过
框架 60 日志别在application.yml配置application.ymllog:path:D:\data\log#日志输出路径level:WARN#输出日志
linux系统 5212 Linux分区挂载点分区类型备注/boot启动分区一般设置100M-200M,boot目录包含了操作系统内核和在启动系统过程所要用到文件。/根分区所有未指定挂载点目录都会放到这个挂载
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7 2021年04月  4 2021年05月  4 2021年06月  1 2021年07月  7 2021年08月  2 2021年09月  8 2021年10月  9 2021年11月  16 2021年12月  14 2022年01月  6
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议
目录
祝愿神州十三飞行乘组平安归来