【发布订阅模式】基于Paho java的MQTT消息格式详解【上】

后续:【发布订阅模式】基于Paho java的MQTT通信实战-搭建客户端【下】



MQTT 简介


MQTT是一个极其轻量级的发布/订阅消息传输协议,适用于网络带宽较低的场合.
它有一个用来指定消息类型的简单标头,有一个基于文本的主题,还有一个任意的二进制有效负载。应用程序可对有效负载采用任何数据格式,比如 JSON、XML、加密二进制或 Base64,只要目标客户端能够解析该有效负载
MQTT 协议基于 TCP/IP 协议,MQTT Broker 和 Client 都有需要有 TCP/IP 地址。

它通过一个代理服务器(broker),任何一个客户端(client)都可以订阅或者发布某个主题的消息,然后订阅了该主题的客户端则会收到该消息。

客户端连接到代理。它可以订阅代理中的任何消息“主题”。此连接可以是简单的 TCP/IP 连接,也可以是用于发送敏感消息的加密 TLS 连接。
客户端通过将消息和主题发送给代理,发布某个主题范围内的消息。
代理然后将消息转发给所有订阅该主题的客户端。

设计原则

MQTT遵循以下设计原则:
精简,不添加可有可无的功能。
发布/订阅(Pub/Sub)模式,方便消息在传感器之间传递。
允许用户动态创建主题,零运维成本。
把传输量降到最低以提高传输效率。
把低带宽、高延迟、不稳定的网络等因素考虑在内。
支持连续的会话控制。
提供服务质量管理。
假设数据不可知,不强求传输数据的类型与格式,保持灵活性。

发布订阅模式是传统 Client/Server 模式的一种解耦方案。
发布者通过 Broker 与消费者之间通信,Broker 的作用是将收到的消息通过某种过滤规则,正确地发送给消费者。发布/订阅模式 相对于 客户端/服务器模式 的好处在于:
发布者和消费者之间不必预先知道对方的存在,比如不需要预先沟通对方的 IP Address 和 Port;发布者和消费者之间不必同时运行。因为 Broker 是一直运行的。

在MQTT协议里,过滤规则==Topic
主题名(Topic Name)用于识别消息应该被发布到哪一个会话,服务端发送给订阅客户端的 Publish 报文的主题名必须匹配该订阅的主题过滤器。Topic是不要预先创建的,发布者发送消息到某个主题、或者订阅者订阅某个主题的时候,Broker 就会自动创建这个主题。
Topic有层级结构,并且支持通配符+和#:

  • “+” 是匹配单层的通配符。比如 news/+ 可以匹配 news/sports,news/+/basketball 可匹配到 news/sports/basketball。
  • “#” 是一到多层的通配符。比如 news/# 可以匹配 news、 news/sports、news/sports/basketball 以及 news/sports/basketball/x 等等。

带宽消耗最小化
MQTT 协议将协议本身占用的额外消耗最小化,消息头部最小只需要占用 2 个字节。如 PINGREQ / PINGRESP 和 DISCONNECT 报文是不需要可变头部的,也没有 Payload,也就是说它们的报文大小仅仅消耗 2 个字节。

MQTT 的消息格式分三部分:

固定长度头部,2 个字节,所有消息类型里都有
可变长度头部,只有某些消息类型里有
Payload,只有某些消息类型里有

三个可选的 QoS 等级
为适应设备不同的网络环境,MQTT 设计了 3 个 QoS 等级:0, 1, 2:
At most once (0)
At least once (1)
Exactly once (2)

QoS 0 是一种 “fire and forget” 的消息发送模式:Sender (可能是 Publisher 或者 Broker) 发送一条消息之后,就不再关心它有没有发送到对方,也不设置任何重发机制。
-可以接受消息偶尔丢失。
-在同一个子网内部的服务间的消息交互,或其他客户端与服务端网络非常稳定的场景。

QoS 1 包含了简单的重发机制,Sender 发送消息之后等待接收者的 ACK,如果没收到 ACK 则重新发送消息。这种模式能保证消息至少能到达一次,但无法保证消息重复。
-对系统资源消耗较为关注,希望性能最优化。
-消息不能丢失,但能接受并处理重复的消息。

QoS 2 设计了略微复杂的重发和重复消息发现机制,保证消息到达对方并且严格只到达一次。
-不能忍受消息丢失(消息的丢失会造成生命或财产的损失),且不希望收到重复的消息。
-数据完整性与及时性要求较高的银行、消防、航空等行业。

在这里插入图片描述
会话保持
MQTT设计了协议层的保活机制:在 CONNECT 报文里可设置 Keepalive 字段,来设置保活心跳包 PINGREQ/PINGRESP 的发送时间间隔。当长时间无法收到设备的 PINGREQ 的时候,Broker 就会认为设备已经下线。
Keepalive 有两个作用:
发现对端死亡或者网络中断
在长时间无消息交互的情况下,保持连接不被网络设备断开

对于那些想要在重新上线后,重新收到离线期间错过的消息的设备,MQTT 设计了持久化连接:在 CONNECT 报文里可设置 CleanSession 字段为 False,则 Broker 会为终端存储–
设备所有的订阅 / 还未被设备确认的 QoS1 和 QoS 消息 / 设备离线时错过的消息

在线状态感知
MQTT 设计了遗愿(Last Will) 消息,让 Broker 在发现设备异常下线的情况下,帮助设备发布一条遗愿消息到指定的主题。
实际上在某些 MQTT 服务器的实现里 (比如 EMQX),设备上线或下线的时候 Broker 会通过某些系统主题发布设备状态更新,更符合实际应用场景。



参数详解

Clean Session

客户端和服务端可以保存会话状态,以支持跨网络连接的可靠消息传输,这个标志告诉服务器这次连接是不是一个全新的连接。

客户端的会话状态包括:
已经发送给服务端,但是还没有完成确认的 QoS 1 和 QoS 2 级别的消息
已从服务端接收,但是还没有完成确认的 QoS 2 级别的消息。

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

如果 CleanSession 标志被设置为 1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间。

如果 CleanSession 标志被设置为 0,服务端必须基于当前会话(使用 ClientId 识别)的状态恢复与客户端的通信。如果没有与这个客户端标识符关联的会话,服务端必须创建一个新的会话。当连接断开后,客户端和服务端必须保存会话信息。

Connack 确认连接请求[broker->client]

客户端发送 Connect 报文请求对服务器的连接,服务器必须发送 Connack 报文作为对 来自客户端的 Connect 报文的回应。如果客户端在合理的时间内没有收到服务端的CONNACK报文,客户端应该关闭网络连接。合理的时间取决于应用的类型和通信基础设施。在 MQTTX 中,可以通过 Connection Timeout 来设置合理的超时时间。
Connack 报文包含 Session Present 和 Connect Return code 两个重要的标志。

Session Present 标志表示当前会话是否是一个新的会话,如果服务端收到 CleanSession 标志为1的连接,Connack报文中的 SessionPresent 标志为 0 。如果服务端收到一个 CleanSession 为0的连接,SessionPresent 标志的值取决于服务端是否已经保存了 ClientId 对应客户端的会话状态。如果服务端已经保存了会话状态,Connack 报文中的 SessionPresent 标志为 1,如果服务端没有已保存的会话状态,Connack 报文中的 SessionPresent 标志为 0.

Connect Return code 表示服务器对此次 Connect 的回应,0 表示连接已被服务器接受。如果服务端收到一个合法的 CONNECT 报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码(表格中的某一个)的 CONNACK 报文。如果服务端发送了一个包含非零返回码的CONNACK 报文,那么它必须关闭网络连接。

Subscribe 订阅主题[client -> broker]

客户端向服务端发送 Subscribe 报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给与那些订阅匹配的主题,服务端发送 Publish 报文给客户端。Subscribe 报文为每个订阅指定了最大的 QoS 等级,服务端根据这个发送应用消息给客户端。
Subscribe 报文的有效载荷必须包含至少一对主题过滤器和QoS等级字段组合。没有有效载荷的 Subscribe 报文是违反协议的。

Suback 订阅确认[broker->client]

服务端发送 Suback 报文给客户端,用于确认它已收到并且正在处理 Subscribe 报文。
Suback 报文包含一个原因码列表,用于指定授予的最大QoS等级或 Subscribe 报文所请求的每个订阅发生的错误,每个原因码对应 Subscribe 报文中的一个主题过滤器。Suback 报文中的原因码顺序必须与 Subscribe 报文中的主题过滤器顺序相匹配
允许的返回码值:
0x00 - 最大QoS 0
0x01 - 成功 – 最大QoS 1
0x02 - 成功 – 最大 QoS 2
0x80 - Failure 失败


 Publish 发布消息

Publish 报文是指从客户端向服务端或者服务端向客户端传输一个应用消息,服务器收到 Publish 报文后根据主题过滤器将消息转发给其他客户端。
Publish 报文不能将 QoS 所有的位设置为 1。如果服务端或客户端收到 QoS 所有位都为 1 的 Publish 报文,它必须关闭网络连接。

如果pub和sub都是2,就是2组4次交互。如果只有pub为2,一组4次交互。但如果pub是1,sub为2,则测试结果和sub,pub都为1的情况一样,sub和broker之间不是4次交互。

Retain

如果客户端发给服务端的 Publish 报文的保留(RETAIN)标志被设置为 1,服务端必须存储这个应用消息和它的服务质量等级(QoS),以便它可以被分发给未来的主题名匹配的订阅者 。一个新的订阅建立时,对每个匹配的主题名,如果存在最近保留的消息,它必须被发送给这个订阅者。如果服务端收到一条保留(RETAIN)标志为1的Q消息,它必须丢弃之前为那个主题保留的任何消息,并将这个新的消息当作那个主题的新保留消息。

保留标志为 1 且有效载荷为零字节的 Publish 报文会被服务端当作正常消息处理,它会被发送给订阅主题匹配的客户端。此外,同一个主题下任何现存的保留消息必须被移除,因此这个主题之后的任何订阅者都不会收到一个保留消息

Payload(数据包的第三部分)

有效载荷包含将被发布的应用消息。数据的内容和格式是应用特定的,可以发送图像,任何编码的文本,加密的数据以及几乎所有二进制数据。
(1)CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。
(2)SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。
(3)SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。
(4)UNSUBSCRIBE,消息体内容是要订阅的主题。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种非常强大的编程语言,它可以实现基于paho mqtt库的连接、订阅和发布功能。首先,我们需要安装paho mqtt库并在代码中引入相关的头文件。 在连接MQTT服务器之前,我们需要设置连接参数,例如服务器地址、端口号、客户端ID等。然后,我们可以使用paho mqtt库中的相关函数创建一个MQTT客户端并连接到服务器。 连接成功后,我们可以使用MQTT订阅函数来订阅感兴趣的主题订阅函数需要设置主题名称和订阅回调函数。当有新的消息到达时,订阅回调函数将触发并处理接收到的消息。 除了订阅主题外,我们还可以使用MQTT发布函数将消息发送给指定的主题。发布函数需要设置主题消息内容。当调用发布函数后,消息将被发送到MQTT服务器,并可以被所有订阅了该主题的客户端接收到。 在使用完MQTT客户端后,我们需要通过调用相关函数来断开与服务器的连接,并释放资源。 总结起来,通过使用C语言和paho mqtt库,我们可以实现基于MQTT的连接、订阅和发布功能。首先,设置连接参数并创建MQTT客户端。然后,使用订阅函数订阅感兴趣的主题,接收和处理接收到的消息。最后,使用发布函数发送消息到指定的主题。最后,断开与服务器的连接并释放资源。这样,我们就可以在C语言中实现基于paho mqtt库的连接、订阅和发布功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值