前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MQTT Packet详解【02】:PUBLISH & PUBACK

MQTT Packet详解【02】:PUBLISH & PUBACK

作者头像
Hello工控
发布于 2025-05-08 08:32:30
发布于 2025-05-08 08:32:30
15000
代码可运行
举报
文章被收录于专栏:Hello工控Hello工控
运行总次数:0
代码可运行

在上期中,我们介绍了MQTT 5.0的CONNECT和CONNACK数据包:

MQTT Packet详解【01】:CONNECT & CONNACK

现在,我们将介绍用于在MQTT中传递应用程序消息的PUBLISH包及其响应包。

无论是客户端向服务器发布消息,还是服务器向订阅者转发消息,都需要PUBLISH数据包。确定消息方向的主题、消息的实际内容和QoS级别都包含在PUBLISH数据包中。

在客户端和服务器端之间的消息传递过程中,除了PUBLISH包外,还有四个包:PUBACK、PUBREC、PUBREL和PUBCOMP。它们用于实现MQTT的QoS 1和QoS 2消息机制。

图片
图片

Sample样例

我们使用MQTTX CLI将三个具有不同QoS级别的消息发布到公共MQTT服务器,并使用Wireshark捕获在客户端和服务器之间来回传输的MQTT数据包。在Linux中,您可以使用tcpdump捕获数据包,然后将其导入Wireshark进行查看。

以下是本示例中使用的MQTTX CLI命令。为了显示PUBLISH数据包的属性,这些命令还设置了Message Expiry Interval和Response Topic属性:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mqttx pub --hostname broker.emqx.io --mqtt-version 5 \  --topic request --qos 0 --message "This is a QoS 0 message" \  --message-expiry-interval 300 --response-topic response

以下是Wireshark捕获的QoS为0的PUBLISH数据包:

此十六进制字节串对应于以下数据包内容:

当我们只修改MQTTX CLI命令中的QoS选项并将其设置为1时,我们将看到服务器在收到PUBLISH后回复PUBACK数据包。它们的数据包如下。

此时,PUBLISH数据包中的第一个字节已从0x30更改为0x32,表明这是一条QoS 1消息。

PUBACK数据包结构相对简单,如您所见,Reason Code为0x10,表示消息已收到,但没有匹配的订阅者。一旦有人订阅了主题请求,PUBACK数据包中的Reason Code就会变为0x00,表示消息已经收到,并且有匹配的订阅者。

继续使用MQTTX CLI发布QoS 2消息,我们将看到客户机和服务器之间有两轮消息交换。Wireshark会告诉我们这些数据包分别是PUBLISH、PUBREC、PUBREL和PUBCOMP,它们都有相同的数据包标识符0x11c2

我们如何从由十六进制字节组成的数据包数据中准确地确定它是否是PUBLISH数据包,它的QoS级别是什么,以及它的响应数据包中的Reason Code是什么?下面对这些数据包的介绍将回答这些问题。

图片
图片

PUBLISH Packet Structure

PUBLISH包结构

Fixed Header固定头

在PUBLISH包的Fixed Header中,第一字节的高4位固定为3(0 b 0011),低4位由以下三个字段组成:

  • DUP(位3):当客户端或服务器重传PUBLISH数据包时,需要将DUP标志设置为1,表示这是一个重传的数据包。在DUP设置为1时,接收到的PUBLISH分组的数量和频率可以揭示当前通信链路的质量。
  • QoS(Bit 2 - 1):用于指定消息的QoS级别。
  • Retain(Bit 0):置1,表示当前消息为保留消息;置0,表示当前消息为正常消息。

在此之后是剩余长度字段,其指示当前分组的剩余部分中的字节数。

Variable Header 变量头

PUBLISH数据包的变量报头按顺序包含以下字段:

  • Topic Name主题名称:这是一个UTF-8编码的字符串,用于指示消息应该发布到哪个通道。
  • Packet Identifier数据包标识符:这是一个双字节的标识符,用于唯一地标识当前正在传输的消息。当QoS级别为1或2时,数据包标识符仅出现在PUBLISH数据包中。
  • Properties属性:下表列出了PUBLISH数据包的所有可用属性。

Payload 载荷

我们发送的应用程序消息的内容存储在PUBLISH数据包的Payload中。它可以携带任何格式的应用程序消息,如JSON、ProtoBuf等

图片
图片

PUBACK Packet Structure PUBACK 数据包结构

Fixed Header固定头

固定报头中第一个字节的高4位固定为4(0b0100),指示这是PUBACK分组。较低的4位被保留并且全部被设置为0。

紧随其后的是剩余长度字段,它指示当前数据包中剩余的字节数。

Variable Header 变量头

PUBACK包的可变头部按顺序包含以下字段:

  • 数据包标识符:与PUBLISH数据包不同,PUBACK数据包中的数据包标识符必须存在。它用于向另一端指示这是对哪个QoS 1 PUBLISH分组的响应。
  • Reason Code原因代码:这是一个单字节字符串,用于向发布者指示发布结果,例如发布是否由于缺乏授权而被拒绝。下表列出了PUBACK数据包的所有可用原因代码:
  • 属性:下表列出了PUBACK数据包的所有可用属性。

Payload 载荷

PUBACK 包没有负载。

图片
图片

PUBREC、PUBREL、PUBCOMP数据包结构

PUBREC、PUBREL、PUBCOMP的包结构与PUBACK基本一致。它们的主要区别在于固定报头中的数据包类型字段的值以及可以使用的原因代码。

数据包类型字段的值为5,表示这是一个PUBREC数据包;如果值为6,表示这是一个PUBREL数据包;如果值为7,表示这是一个PUBCOMP数据包。

PUBREC作为QoS 2消息流中PUBLISH报文的确认报文,可以使用与PUBACK完全相同的原因码。如下图所示:

PUBREL和PUBCOMP数据包可用的原因代码如下:

结论

PUBLISH包中的Topic决定了消息的方向,QoS决定了消息的可靠性。它还确定在传输期间将使用哪些数据包。PUBACK数据包用于QoS 1消息,PUBREC、PUBREC和PUBCOMP数据包用于QoS 2消息。当QoS大于0时,数据包还需要包含数据包标识符,以将PUBLISH数据包与其响应数据包相关联。

PUBLISH数据包的Payload不限制数据类型,因此我们可以传输任何格式的应用程序消息。此外,属性Properties可以满足我们更多场景的需求。例如,Topic Expiry可以减少每条消息的大小,Message Expiry Interval可以为时间敏感的消息设置过期时间等等。

PUBLISH包的这些响应包不仅向发送方表示消息已经收到,还通过Reason Code进一步表示发布结果。所以当订阅者无法接收消息时,我们也可以通过发布者收到的响应包中的原因代码来排查问题。

参考链接:

  1. http://www.steves-internet-guide.com/mqtt-publish-subscribe/
  2. https://www.emqx.com/en/blog/mqtt-5-0-control-packets-02-publish-puback
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Hello工控 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Sample样例
  • PUBLISH Packet Structure
    • Variable Header 变量头
    • Payload 载荷
  • PUBACK Packet Structure PUBACK 数据包结构
    • Payload 载荷
    • PUBACK 包没有负载。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档