MQTT协议总结

1. MQTT控制报文的格式

1.1 MQTT控制报文的结构

MQTT控制报文的结构
Fixed header 固定报头,所有控制报文都包含
Variable header 可变报头,部分控制报文包含
Payload 有效载荷,部分控制报文包含

1.2 固定报头(2个字节)






















Bit 7 6 5 4 3 2 1 0
byte 1 MQTT控制报文的类型 用于指定控制报文类型的标志位
byte 2 剩余长度
1.2.1 控制报文的类型(14种)–高四位
名字 报文流动方向 描述
Reserved 0 禁止 保留
CONNECT 1 客户端到服务端 客户端请求连接服务端
CONNACK 2 服务端到客户端 连接报文确认
PUBLISH 3 两个方向都允许 发布消息
PUBACK 4 两个方向都允许 QoS 1 消息发布收到确认
PUBREC 5 两个方向都允许 发布收到(保证交付第一步)
PUBREL 6 两个方向都允许 发布释放(保证交付第二步)
PUBCOMP 7 两个方向都允许 QoS 2 消息发布完成(保证交互第三步)
SUBSCRIBE 8 客户端到服务端 客户端订阅请求
SUBACK 9 服务端到客户端 订阅请求报文确认
UNSUBSCRIBE 10 客户端到服务端 客户端取消订阅请求
UNSUBACK 11 服务端到客户端 取消订阅报文确认
PINGREQ 12 客户端到服务端 心跳请求
PINGRESP 13 服务端到客户端 心跳响应
DISCONNECT 14 客户端到服务端 客户端断开连接
Reserved 15 禁止 保留
1.2.2 标志位 –低四位
控制报文 固定报头标志 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PUBLISH Used in MQTT 3.1.1 DUP 1 QoS 2 QoS 2 RETAIN 3
PUBACK Reserved 0 0 0 0
PUBREC Reserved 0 0 0 0
PUBREL Reserved 0 0 1 0
PUBCOMP Reserved 0 0 0 0
SUBSCRIBE Reserved 0 0 1 0
SUBACK Reserved 0 0 0 0
UNSUBSCRIBE Reserved 0 0 1 0
UNSUBACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0
1.2.3 剩余长度 –从第 2 个字节开始位置

剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。

剩余长度字段使用一个变长度编码方案,对小于 128 的值它使用单字节编码。更大的值按下面的方式处理。低 7 位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码 128 个数值和一个 延续位( continuation bit ) 。剩余长度字段最大 4 个字节。

分别表示(每个字节的低 7 位用于编码数据,最高位是标志位):
1 个字节时,从 0(0x00)到 127(0x7f)
2 个字节时,从 128(0x80,0x01)到 16383(0Xff,0x7f)
3 个字节时,从 16384(0x80,0x80,0x01)到 2097151(0xFF,0xFF,0x7F)
4 个字节时,从 2097152(0x80,0x80,0x80,0x01)到 268435455(0xFF,0xFF,0xFF,0x7F)

1.3 可变报头

某些 MQTT 控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。

很多控制报文的可变报头部分包含一个两字节的报文标识符字段。这些报文是 PUBLISH(QoS>0 时),PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE, SUBACK,UNSUBSCIBE,UNSUBACK。

注意:QoS 设置为 0 的 PUBLISH 报文 不能包含报文标识符。PUBACK, PUBREC, PUBREL 报文 必须包含与最初发送的 PUBLISH 报文相同的报文标识符。类似地,SUBACK 和 UNSUBACK 必须包含在对应的 SUBSCRIBE 和 UNSUBSCRIBE 报文中使用的
报文标识符。

1.4 有效载荷

某些 MQTT 控制报文在报文的最后部分包含一个有效载荷。对于PUBLIC来说,有效载荷就是应用消息。

1.4.1 包含有效载荷的控制报文
控制报文 有效载荷
CONNECT 需要
CONNACK 不需要
PUBLISH 可选
PUBACK 不需要
PUBREC 不需要
PUBREL 不需要
PUBCOMP 不需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
PINGRESP 不需要
DISCONNECT 不需要

2. MQTT控制报文(14种)

2.1 CONNECT – 连接服务端

客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文。
在一个网络连接上,客户端只能发送一次 CONNECT 报文。服务端 必须将客户端发送的第二个 CONNECT报文当作协议违规处理并断开客户端的连接。有效载荷包含一个或多个编码的字段。包括客户端的唯一标识符,Will 主题,Will 消息,用户名和密码。除了客户端标识之外,其它的字段都是可选的,基于标志位来决定可变报头中是否需要包含这些字段。

2.2 CONNACK – 确认连接请求

服务端发送 CONNACK 报文响应从客户端收到的 CONNECT 报文。服务端发送给客户端的第一个报文必须须是 CONNACK。如果客户端在合理的时间内没有收到服务端的 CONNACK 报文,客户端 应该关闭网络连接。合理的时间取决于应用的类型和通信基础设施。

连接返回码的值
返回码响应 描述
0 0x00 连接已接受 连接已被服务端接受
1 0x01 连接已拒绝,不支持的协议版本 服务端不支持客户端请求的 MQTT 协议级别
2 0x02 连接已拒绝,不合格的客户端标识符 客户端标识符是正确的 UTF-8 编码,但服务端不允许使用
3 0x03 连接已拒绝,服务端不可用 网络连接已建立,但 MQTT 服务不可用
4 0x04 连接已拒绝,无效的用户名或密码 用户名或密码的数据格式无效
5 0x05 连接已拒绝,未授权 客户端未被授权连接到此服务器
6-255 保留

如果认为上表中的所有连接返回码都不太合适,那么服务端 必须关闭网络连接,不需要发送 CONNACK 报文。

2.3 PUBLISH – 发布消息

PUBLISH 控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息。

PUBLISH 报文固定报头























Bit 7 6 5 4 3 2 1 0
byte 1 MQTT控制报文的类型 DUP(重发标志) QoS等级 RETAIN
byte 2 剩余长度

备注:① 如果 DUP 标志被设置为 0,表示这是客户端或服务端第一次请求发送这个 PUBLISH 报文。如果 DUP 标志被设置为 1,表示这可能是一个早前报文请求的重发。② QoS=0表示最多分发1次、QoS=1表示至少分发一次、QoS=2表示只分发一次。③ 如果客户端发给服务端的 PUBLISH 报文的保留标志位 0,服务端 不能存储这个消息也 不能移除或替换任何现存的保留消息。④ 服务端发送给订阅客户端的 PUBLISH 报文的主题名 必须匹配该订阅的主题过滤器。

2.4 PUBACK – 发布确认

PUBACK 报文是对 QoS 1 等级的 PUBLISH 报文的响应。

2.5 PUBREC – 发布收到

PUBREC 报文是对 QoS 等级 2 的 PUBLISH 报文的响应。它是 QoS 2 等级协议交换的第二个报文。

2.6 PUBREL – 发布释放

PUBREL 报文是对 PUBREC 报文的响应。它是 QoS 2 等级协议交换的第三个报文。

2.7 PUBCOMP – 发布完成

PUBCOMP报文是对PUBREL报文的响应。它是QoS 2等级协议交换的第四个也是最后一个报文。

2.8 SUBSCRIBE - 订阅主题

客户端向服务端发送 SUBSCRIBE 报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给与那些订阅匹配的主题,服务端发送 PUBLISH 报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的 QoS 等级,服务端根据这个发送应用消息给客户端。SUBSCRIBE 报文的有效载荷包含了一个主题过滤器列表,它们表示客户端想要订阅的主题。每一个过滤器后面跟着一个字节,这个字节被叫做服务质量要求(Requested QoS)。它给出了服务端向客户端发送应用消息所允许的最大 QoS 等级。SUBSCRIBE 报文的有效载荷 必须包含至少一对主题过滤器 和 QoS 等级字段组合。服务端收到客户端发送的一个 SUBSCRIBE 报文时, 必须使用 SUBACK 报文响应SUBACK 报文 必须和等待确认的 SUBSCRIBE 报文有相同的报文标识符。

2.9 SUBACK – 订阅确认

服务端发送 SUBACK 报文给客户端,用于确认它已收到并且正在处理 SUBSCRIBE 报文。SUBACK 报文包含一个返回码清单,它们指定了 SUBSCRIBE 请求的每个订阅被授予的最大 QoS 等级。SUBACK有效载荷包含一个返回码清单。每个返回码对应等待确认的 SUBSCRIBE 报文中的一个主题过滤器。返回码的顺序 必须和 SUBSCRIBE 报文中主题过滤器的顺序相同。

2.10 UNSUBSCRIBE – 取消订阅

客户端发送 UNSUBSCRIBE 报文给服务端,用于取消订阅主题。UNSUBSCRIBE 报文固定报头的第 3,2,1,0 位是保留位且 必须分别设置为 0,0,1,0。服务端 必须认为任何其
它的值都是不合法的并关闭网络连接。UNSUBSCRIBE 报文的有效载荷 必须至少包含一个消息过滤器。

2.11 UNSUBACK – 取消订阅确认

服务端发送 UNSUBACK 报文给客户端用于确认收到 UNSUBSCRIBE 报文。

2.12 12 PINGREQ – 心跳请求

客户端发送 PINGREQ 报文给服务端的。用于:

  1. 在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
  2. 请求服务端发送 响应确认它还活着。
  3. 使用网络以确认网络连接没有断开。

—注意:保持连接(Keep Alive)处理中用到这个报文

2.13 PINGRESP – 心跳响应

服务端发送 PINGRESP 报文响应客户端的 PINGREQ 报文。表示服务端还活着。

—注意:保持连接(Keep Alive)处理中用到这个报文

2.14 DISCONNECT – 断开连接

DISCONNECT 报文是客户端发给服务端的最后一个控制报文。表示客户端正常断开连接。
服务端在收到 DISCONNECT 报文时:

  1. 必须丢弃任何与当前连接关联的未发布的遗嘱消息。
  2. 应该关闭网络连接,如果客户端还没有这么做。

3. 服务质量等级

3.1 QoS 0: 最多分发一次

消息的分发依赖于底层网络的能力。接收者不会发送响应,发送者也不会重试。消息可能送达一次也可能根本没送达。

  1. 对于 QoS 0 的分发协议,发送者必须发送 QoS 等于 0,DUP 等于 0 的 PUBLISH 报文。
  2. 对于 QoS 0 的分发协议,接收者接受 PUBLISH 报文时同时接受消息的所有权。

3.2 QoS 1: 至少分发一次(推荐)

服务质量确保消息至少送达一次。QoS 1 的 PUBLISH 报文的可变报头中包含一个报文标识符,需要PUBACK 报文确认。

3.2.1 对于QoS 1的分发协议,发送者
  1. 每次发送新的应用消息都必须分配一个未使用的报文标识符。
  2. 发送的 PUBLISH 报文 必须包含报文标识符且 QoS 等于 1,DUP 等于 0。
  3. 必须将这个 PUBLISH 报文看作是未确认的 ,直到从接收者那收到对应的 PUBACK 报文。一旦发送者收到 PUBACK 报文,这个报文标识符就可以重用。
3.2.2 对于 QoS 1 的分发协议,接收者
  1. 响应的 PUBACK 报文 必须包含一个报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH 报文。
  2. 发送了 PUBACK 报文之后,接收者必须将任何包含相同报文标识符的入站 PUBLISH 报文当作一个新的消息,并忽略它的 DUP 标志的值。

3.3 QoS 2: 仅分发一次

这是最高等级的服务质量,消息丢失和重复都是不可接受的。使用这个服务质量等级会有额外的开销。

3.3.1 对于 QoS 2 的分发协议,发送者
  1. 必须给要发送的新应用消息分配一个未使用的报文标识符。
  2. 发送的 PUBLISH 报文 必须包含报文标识符且报文的 QoS 等于 2,,DUP 等于 0。
  3. 必须将这个 PUBLISH 报文看作是 未确认的 ,直到从接收者那收到对应的 PUBREC 报文。
  4. 收到 PUBREC 报文后 必须发送一个 PUBREL 报文。PUBREL 报文必须包含与原始 PUBLISH 报文相同的报文标识符。
  5. 必须将这个 PUBREL 报文看作是未确认的 ,直到从接收者那收到对应的 PUBCOMP 报文。
  6. 一旦发送了对应的 PUBREL 报文就 不能重发这个 PUBLISH 报文。一旦发送者收到 PUBCOMP 报文,这个报文标识符就可以重用。

注意:允许发送者在等待确认时使用不同的报文标识符发送后续的 PUBLISH 报文。

3.3.2 对于QoS 2的分发协议,接收者
  1. 响应的 PUBREC 报文 必须包含报文标识符,这个标识符来自接收到的、已经接受所有权的
    PUBLISH 报文。
  2. 在收到对应的 PUBREL 报文之前,接收者 必须发送 PUBREC 报文确认任何后续的具有相同标识符的 PUBLISH 报文。 在这种情况下,它不能重复分发消息给任何后续的接收者。
  3. 响应 PUBREL 报文的 PUBCOMP 报文 必须包含与 PUBREL 报文相同的标识符。
  4. 发送 PUBCOMP 报文之后,接收者必须将包含相同报文标识符的任何后续 PUBLISH 报文当作一个新的发布。
Hawky wechat
欢迎订阅我的微信公众号
坚持原创技术分享,您的支持将鼓励我继续创作!

分享