欢迎阅读 MQTT 5.0 报文系列 的第二篇文章。在上一篇中,我们已经介绍了 MQTT 5.0 的 CONNECT 和 CONNACK 报文。现在,我们将介绍在 MQTT 中用于传递应用消息的 PUBLISH 报文以及它的响应报文。 不管是客户端向服务端发布消息,还是服务端向订阅端转发消息,都需要使用 PUBLISH 报文。决定消息流向的主题、消息的实际内容和 QoS 等级,都包含在 PUBLISH 报文中。 客户端与服务端在消息传递的过程中,除了 PUBLISH 报文,还会用到 PUBACK、PUBREC、PUBREL、PUBCOMP 这四个报文,它们分别用于实现 MQTT 的 QoS 1 和 QoS 2 消息机制。在本文中,我们将深入研究这五个报文的组成。 报文示例我们使用 MQTTX CLI 向 公共 MQTT 服务器 发布三条不同 QoS 等级的消息,并使用 Wireshark 工具抓取在客户端与服务器之间往返的 MQTT 报文,Linux 环境可以使用 tcpdump命令抓取报文,然后导入至 Wireshark 分析。 以下是本示例使用的 MQTTX CLI 命令,为了展示 PUBLISH 报文的属性字段,命令中还设置了 Message Expiry Interval 和 Response Topic 属性: mqttx pub --hostname broker. --mqtt-version 5 \ --topic request --qos 0 --message "This is a QoS 0 message" \ --message-expiry-interval 300 --response-topic response 以下是 Wireshark 抓取到的 MQTTX CLI 发出的 QoS 为 0 的 PUBLISH 报文: 30 31 00 07 72 65 71 75 65 73 74 10 02 00 00 01 2c 08 00 08 72 65 73 70 6f 6e 73 65 54 68 69 73 20 69 73 20 61 20 51 6f 53 20 30 20 6d 65 73 73 61 67 65 这串十六进制字节,对应以下报文内容: 而当我们仅修改 MQTTX CLI 命令中的 QoS 选项,将消息的 QoS 等级设置为 1,我们将看到服务端在收到 PUBLISH 后回复了 PUBACK 报文,他们的报文数据分别为: Client -- PUBLISH (32 33 00 .. ..) -> ServerClient <- PUBACK (40 04 64 4a 10 00) -- Server 此时 PUBLISH 报文中第一个字节从 0x30 变成了 0x32,表示这是一条 QoS 1 消息。 PUBACK 的报文结构比较简单,可以看到 Reason Code 为 继续使用 MQTTX CLI 发布一条 QoS 2 消息,我们将看到客户端和服务端之间发生了两次报文往返,Wireshark 会告诉我们,这些报文分别是 PUBLISH、PUBREC、PUBREL 以及 PUBCOMP,并且它们拥有相同的报文标识符 Client -- PUBLISH (34 33 00 .. ..) -> ServerClient <- PUBREC (50 04 11 c2 10 00) -- ServerClient -- PUBREL (62 03 11 c2 00) -> ServerClient <- PUBCOMP (70 04 11 c2 00 00) -- Server 如何从由十六进制字节组成的报文数据中准确地知道这是否是一个 PUBLISH 报文,它的 QoS 是多少,它的响应报文中的原因码又是多少,接下来对这些报文的介绍将会回答这些问题。 PUBLISH 报文结构固定报头PUBLISH 报文的固定报头中,首字节的高 4 位的值固定为 3(0b0011),低 4 位则由以下三个字段组成:
紧随其后的是剩余长度(Remaining Length)字段,指示了当前报文剩余部分的字节数。 可变报头PUBLISH 报文的可变报头按顺序包含以下字段:
有效载荷我们发送的应用消息的实际内容,就存放在 PUBLISH 报文的有效载荷中,它可以承载任意格式的应用消息,比如 JSON、ProtoBuf 等等。 PUBACK 报文结构固定报头固定报头中首字节的高 4 位的值固定为 4(0b0100),表示这是一个 PUBACK 报文,低 4 位是保留位,固定全部为 0。 紧随其后的是剩余长度(Remaining Length)字段,指示了当前报文剩余部分的字节数。 可变报头PUBACK 报文的可变报头按顺序包含以下字段:
有效载荷PUBACK 报文不包含有效载荷。 PUBREC、PUBREL、PUBCOMP 报文结构PUBREC、PUBREL 和 PUBCOMP 的报文结构与 PUBACK 基本一致,它们的区别主要在于固定报头中报文类型字段的值,以及可以使用的原因码。 报文类型字段的值为 5(0b0101),表示这是一个 PUBREC 报文;值为 6(0b0110),则表示这是一个 PUBREL报文;值为 7(0b0111),则表示这是一个 PUBCOMP 报文。 PUBREC 作为 QoS 2 消息流程中对 PUBLISH 报文的确认报文,它可以使用的原因码与 PUBACK 完全一致。PUBREL 和 PUBCOMP 报文可用的原因码如下:
总结PUBLISH 报文中的主题决定了消息的流向,QoS 则决定了消息的可靠性,同时也决定了传输时将用到哪些报文,PUBACK 报文用于 QoS 1 消息,PUBREC、PUBREC 和 PUBCOMP 报文用于 QoS 2 消息。QoS 大于 0 时报文中还需要包含报文标识符来关联 PUBLISH 报文和它的响应报文。 PUBLISH 报文的有效载荷不限制数据类型,所以我们可以传输任意格式的应用消息。另外,属性可以满足我们在更多场景下的需要,比如主题别名可以减少每个消息的大小,消息过期间隔可以为有时效性的消息设置过期时间等等。 PUBLISH 报文的响应报文除了向发送端指示消息被接收以外,还能通过 Reason Code 进一步指示发布结果。所以当订阅端迟迟无法收到消息,我们还可以通过发布端收到的响应报文中的原因码来排查问题。 以上就是对 MQTT PUBLISH 及其响应报文的介绍,在下一篇文章中,我们将继续研究订阅和取消订阅报文的结构和组成。 |
|