• MQTT 协议学习: QoS等级 与 会话


    --- title: protocol-app-mqtt-Qos-Session date: 2020-02-03 14:16:51 categories: tags: - mqtt - protocol ---

    背景

    QoS 等级 与 通信的流程有关,直接影响了整个通信。而且篇幅比较长,所以我觉得应该单独拎出来讲一下。

    概念

    QoS 代表了 服务质量等级。 设置上,由2 位 的二进制控制,且值不允许为 3(0x11)。

    QoS值 Bit 2 Bit 1 描述
    0 0 0 最多分发一次
    1 0 1 至少分发一次
    2 1 0 只分发一次
    - 1 1 保留位

    要注意的是,QoS 是 SenderReceiver 之间达成的协议,不是 PublisherSubscriber 之间达成的协议。

    也就是说 Publisher 发布一条 QoS1 的消息,只能保证 Broker 能至少收到一次这个消息;至于对应的 Subscriber 能否至少收到一次这个消息,还要取决于 SubscriberSubscribe 的时候和 Broker 协商的 QoS 等级。

    这里又牵扯出一个概念:"QoS 降级":在 MQTT 协议中,从 Broker 到 Subscriber 这段消息传递的实际 QoS 等于 "Publisher 发布消息时指定的 QoS 等级和 Subscriber 在订阅时与 Broker 协商的 QoS 等级,这两个 QoS 等级中的最小那一个。"

    QoS 0 的通信时序图

    此时,整个过程中的 Sender 不关心 Receiver 是否收到消息,它"尽力"发完消息,至于是否有人收到,它不在乎。

    %% 时序图 sequenceDiagram title : QoS 0:At most one(Fire and forget) participant 发布者 participant 服务器 participant 订阅者 发布者 ->> + 服务器: PUBLISH (QoS0,Msg-A) 服务器 ->> 订阅者: PUBLISH(QoS0,Msg-A) 发布者 ->> 发布者: Delete Msg-A

    QoS1 的通信时序图

    此时,Sender 发送的一条消息,Receiver 至少能收到一次,也就是说 SenderReceiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,但是因为重传的原因,Receiver 有可能会收到重复的消息;

    %% 时序图 sequenceDiagram participant 发布者 participant 服务器 participant 订阅者 title : QoS 1:At least one 发布者->>发布者: Store (Msg-A) 发布者 ->> 服务器: PUBLISH (QoS1,Msg-A) 服务器->>服务器: Store (Msg-A) 服务器 ->> 订阅者: PUBLISH (QoS1,Msg-A) 服务器 -->> 发布者: PUBACK (QoS1) 发布者->>发布者: Delete (Msg-A) 订阅者 -->> 服务器: PUBACK (QoS1,Msg-A) 服务器->>服务器: Delete (Msg-A)

    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 2 的通信时序图

    QoS2 不仅要确保 Receiver 能收到 Sender 发送的消息,还要保证消息不重复。它的重传和应答机制就要复杂一些,同时开销也是最大的。

    Sender 发送的一条消息,Receiver 确保能收到而且只收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。

    %% 时序图 sequenceDiagram participant 发布者 participant 服务器 participant 订阅者 title : QoS 2:Exactly one 发布者->>发布者: Store (Msg-A) 发布者 ->> 服务器: PUBLISH (QoS2,Msg-A,DUP=0) 服务器->>服务器: Store (Msg-A) 服务器 -->> 发布者: PUBREC (QoS2,Msg-A) 发布者 ->> 服务器: PUBREL (QoS2,Msg-A) 服务器 ->> 订阅者 : PUBLISH (QoS2,Msg-A,DUP=0) 服务器 -->> 发布者: PUBCOMP (QoS2,Msg-A) 发布者->>发布者: Delete (Msg-A) 订阅者->>订阅者: Store (Msg-A) 订阅者 -->> 服务器: PUBREC (QoS2,Msg-A) 服务器 ->> 订阅者: PUBREL (QoS2,Msg-A) 订阅者->>订阅者: Notify (Msg-A) 订阅者 -->> 服务器: PUBCOMP (QoS2,Msg-A) 服务器->>服务器: Delete (Msg-A) 订阅者->>订阅者: Delete (Msg-A)

    QoS 使用 2 套请求/应答流程(一个 4 段的握手)来确保 Receiver 收到来自 Sender 的消息,且不重复:

    1)Sender 发送 QoS 为 2 的 PUBLISH 数据包,数据包 Packet Identifier 为 P,并在本地保存该 PUBLISH 包;

    2)Receiver 收到 PUBLISH 数据包以后,在本地保存 PUBLISH 包的 Packet Identifier P,并回复 Sender 一个 PUBREC 数据包,PUBREC 数据包可变头中的 Packet Identifier 为 P,没有消息体(Payload);

    3)当 Sender 收到 PUBREC,它就可以安全地丢弃掉初始的 Packet Identifier 为 P 的 PUBLISH 数据包,同时保存该 PUBREC 数据包,同时回复 Receiver 一个 PUBREL 数据包,PUBREL 数据包可变头中的 Packet Identifier 为 P,没有消息体;如果 Sender 在一定时间内没有收到 PUBREC,它会把 PUBLISH 包的 DUP 标识设为 1,重新发送该 PUBLISH 数据包(Payload);

    4)当 Receiver 收到 PUBREL 数据包,它可以丢弃掉保存的 PUBLISH 包的 Packet Identifier P,并回复 Sender 一个 PUBCOMP 数据包,PUBCOMP 数据包可变头中的 Packet Identifier 为 P,没有消息体(Payload);

    5)当 Sender 收到 PUBCOMP 包,那么它认为数据包传输已完成,它会丢弃掉对应的 PUBREC 包。如果 Sender 在一定时间内没有收到 PUBCOMP 包,它会重新发送 PUBREL 数据包。

    我们可以看到在 QoS2 中,完成一次消息的传递,Sender 和 Reciever 之间至少要发送四个数据包,QoS2 是最安全也是最慢的一种 QoS 等级了。

    QoS 和会话(Session)

    客户端的会话状态包括:

    • 已经发送给服务端,但是还没有完成确认的QoS 1和QoS 2级别的消息
    • 已从服务端接收,但是还没有完成确认的QoS 2级别的消息。

    服务端的会话状态包括:

    • 会话是否存在,即使会话状态的其它部分都是空。
    • 客户端的订阅信息。
    • 已经发送给客户端,但是还没有完成确认的QoS 1和QoS 2级别的消息。
    • 即将传输给客户端的QoS 1和QoS 2级别的消息。
    • 已从客户端接收,但是还没有完成确认的QoS 2级别的消息。
    • 可选,准备发送给客户端的QoS 0级别的消息。

    保留消息不是服务端会话状态的一部分,会话终止时不能删除保留消息。

    如果 Client 想接收离线消息,必须使用持久化的会话(CONNECT报文中可变头(byte8[1])Clean Session = 0)连接到 Broker,这样 Broker 才会存储 Client 在离线期间没有确认接收的 QoS 大于 1 的消息。

    QoS 等级的选择

    在以下情况下你可以选择 QoS0

    • Client 和 Broker 之间的网络连接非常稳定,例如一个通过有线网络连接到 Broker 的测试用 Client;
    • 可以接受丢失部分消息,比如你有一个传感器以非常短的间隔发布状态数据,所以丢一些也可以接受;
    • 你不需要离线消息。

    在以下情况下你应该选择 QoS1:

    • 你需要接收所有的消息,而且你的应用可以接受并处理重复的消息;
    • 你无法接受 QoS2 带来的额外开销,QoS1 发送消息的速度比 QoS2 快很多。

    在以下情况下你应该选择 QoS2:

    • 你的应用必须接收到所有的消息,而且你的应用在重复的消息下无法正常工作,同时你也能接受 QoS2 带来的额外开销。

    实际上,QoS1 是应用最广泛的 QoS 等级,QoS1 发送消息的速度很快,而且能够保证消息的可靠性。虽然使用 QoS1 可能会收到重复的消息,但是在应用程序里面处理重复消息,通常并不是件难事。

  • 相关阅读:
    8皇后问题
    初级8皇后问题
    某个集合的子集问题
    n全排列输出和 n个数的组合(数字范围a~b)
    (转)李明博:我的12年等于24年 快速提升的秘诀是什么 别人以为我早起是先天的,事实靠的是努力 训练,除了反复的努力之外没有什么别的秘诀 像企业主一样去思考,一样查找问题,一同去解决它,并且还要制定出比企业主要求更高的目标。李明博像我一样,不,他比我更把公司当成自己的
    (转)当别人努力的时候,你在做什么? 评论事情的一种态度 当你在抱怨的时候,为什么不想想我做了什么? 把简单的原则坚持贯彻下去 消极的心态,养成了惯性的思维,一切都是不好的。 也许这就是人性的弱点,不经意的习惯,却逐渐腐蚀了你的人生。
    对于保险的看法和如何拒绝保险推销 保险应该主要是有2个主要作用: 1. 分担风险 2. 投资 保险的常用推销方法和该保险的卖点 拒绝保险的方法
    业务、架构、技术,我们应该关注什么 Java和.Net的优势劣势简单看法 市场经济决定,商业之道即是软件之道,市场的需求决定着软件技术的发展 利益决定着选择应用新技术
    我的学习工作经历,一个园林专业中专毕业生的IT之路 学习编程 创业
    “医疗信息化行业之中的联发科”- 我们在医疗行业中的定位及目标 想做一个面对中小企业的专业上游软件供应商 台湾联发科技颠覆掉的是一个封闭的手机产业系统 解决方案,即AgileHIS.NET数字化医院基础方案
  • 原文地址:https://www.cnblogs.com/schips/p/12262587.html
Copyright © 2020-2023  润新知