MQTT报文协议

MQTT通讯协议的特点

 

 

0.控制报文的结构

MQTT控制报文由三部分组成:固定报头  可变报头 有效载荷

0.1 固定报头

每个 MQTT 控制报文都包含一个固定报头。固定报头的数据长度为 2~5字节。(Byte = 8bit)

固定报头的格式:(MSB,高位在前)

  • 剩余长度字段的长度,取决于帧长度。

0.1.1 控制报文的类型

位置:固定报头中,第 1 个字节的 Bit 7~4

控制报文的定义如下:(0/15是保留位,无用。有效类型为 1~14)

  • Qos:Quality of service,服务质量。Qos 0/1/2 为MQTT规定的服务质量等级,其代表消息传递时不同的可靠程度
  • 其中,5、6、7为 Qos2时才会有的控制报文

0.0.2 控制报文类型的标志位

 位置:固定报头中,第 1 个字节的 Bit 3~0

  • DUP1 =控制报文的重复分发标志
  • QoS2 = PUBLISH报文的服务质量等级
  • RETAIN3 = PUBLISH报文的保留标志
  • PUBLISH控制报文中的DUP。

0.0.3 剩余长度

  • 位置:固定报头中,从第2个字节开始
  • 剩余长度等于可变报头的长度(10字节)加上有效载荷的长度
  • 剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据
  • 剩余长度不包括用于编码剩余长度字段本身的字节数。

剩余长度字段 的帧格式:

  • 剩余长度字段 的字节长度:最少1个字节,最多4个字节。
  • 剩余长度字段 可以表示的长度:1个字节时,可以表示剩余 0~127 长度。4个字节时,最大表示长度为 2^(7*4) - 1 = 2^28 - 1 = 268435455 长度

提示:
       之所以1个字节不能表示 2^8 - 1 = 255长度,是因为:每个字节的最高位 Bit7,并不表示数据,是进位标志位。

       剩余长度的计算:
示例1:
       假设本帧剩余字节为 200,计算剩余长度字段。

       使用电脑计算器,将 200 转换为二进制 1100 1000(MSB高位在前)
       从右侧低位每7Bit进行一次拆分,依次拆分出:
       第1个字节为 100 1000,有进位,高位加上进位1为 1100 1000 = 0xC8 (16进制)。
       第2个字节为 1,无进位,为 1 = 0x01 (16进制)。
       那么对应的 字节长度的帧格式如下表:

示例2:
       假设本帧剩余字节为 1000,计算剩余长度字段。

       使用电脑计算器,将 1000 转换为二进制 11 1110 1000(MSB高位在前)
       从右侧低位每7Bit进行一次拆分,依次拆分出:
       第1个字节为 110 1000,有进位,高位加上进位1为 1110 1000 = 0xE8 (16进制)。
       第2个字节为 11 1,无进位,为 11 1 = 0x07 (16进制)。
       那么对应的 字节长度的帧格式如下表:

示例3:
       假设本帧剩余字节为 100,000,000,计算剩余长度字段。

       使用电脑计算器,将 100,000,000 转换为二进制 101 1111 0101 1110 0001 0000 0000(MSB高位在前)
       从右侧低位每7Bit进行一次拆分,依次拆分出:
       第1个字节为 000 0000,有进位,高位加上进位1为 1000 0000 = 0x80 (16进制)。
       第2个字节为 10 0001 0,有进位,高位加上进位1为 1100 0010 = 0xC2 (16进制)。
       第3个字节为 1 0101 11,有进位,高位加上进位1为 1101 0111 = 0xD7 (16进制)。
       第4个字节为 101 111 = 00,无进位,为 10 1111 = 0x2F (16进制)。
       那么对应的 字节长度的帧格式如下表:

0.2 可变报头 

       某些 MQTT 控制报文包含一个可变报头部分。它在固定报头和负载之间。

       可变报头的内容根据报文类型的不同而不同。

       可变报头的报文标识符(Packet Identifier)字段存在于多个类型的报文里。

0.3 有效载荷

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

1.心跳

1.1 心跳请求(PINGREQ)

       PINGREQ 只有固定报头字段,且报文长度只有 2 字节。

       PINGREQ 没有 可变报头 字段。

       PINGREQ 没有 有效载荷 字段。

       响应:服务端必须发送 PINGRESP报文响应客户端的PINGREQ报文。

1.2心跳响应(PINGRESP)

       PINGRESP 只有固定报头字段,且报文长度只有 2 字节。

       PINGRESP 没有 可变报头 字段。

       PINGRESP 没有 有效载荷 字段。

2.连接

2.1 CONNECT - 连接服务器

  • 客户端到服务端的TCP/UDP网络连接建立后,客户端发送给服务端的第一条报文必须是 CONNECT 报文
  • 在一个网络连接上,客户端只能发送一次 CONNECT 报文
  • 服务端必须将客户端发送的第二个 CONNECT 报文当作协议违规。

 

2.1.1 connect固定报文头 

  • CONNECT 的第1个字节为 0x10,剩余长度字段需要根据可变报头和有效载荷的长度来确定。
  • 剩余长度字段的计算过程见 2.2.3。

 2.1.2 CONNECT 可变报头

       CONNECT的可变报头包含四个字段:

  • 协议名(Protocol Name)

       可变报头中,协议名字段的6个字节是固定的:

  • 协议级别(Protocol Level)

        客户端用8位的无符号值表示协议的修订版本。对于3.1.1版MQTT协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接。

  • 连接标志(Connect Flags)

       连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。

       Bit 1:清理会话标志位。这个标志位用于控制会话状态的生存时间。如果清理会话(CleanSession)标志被设置为0,服务端必须基于当前会话(使用客户端标识符识别)的状态恢复与客户端的通信;如果清理会话(CleanSession)标志被设置为1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间。与这个会话关联的状态数据不能被任何之后的会话重用。

       Bit 2:遗嘱标志位。遗嘱标志(Will Flag)被设置为1,表示如果连接请求被接受了,遗嘱(Will Message)消息必须被存储在服务端并且与这个网络连接关联。之后网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到DISCONNECT报文时删除了这个遗嘱消息。如果遗嘱标志被设置为1,连接标志中的Will QoS和Will Retain字段会被服务端用到,同时有效载荷中必须包含Will Topic和Will Message字段。

       Bit 3~4:遗嘱 Qos。这两位用于指定发布遗嘱消息时使用的服务质量等级。如果遗嘱标志被设置为0,遗嘱QoS也必须设置为0(0x00)。如果遗嘱标志被设置为1,遗嘱QoS的值可以等于0(0x00),1(0x01),2(0x02)。它的值不能等于3。

       Bit 5:遗嘱保留标志位。如果遗嘱消息被发布时需要保留,需要指定这一位的值。如果遗嘱标志被设置为0,遗嘱保留(Will Retain)标志也必须设置为0。如果遗嘱标志被设置为1:

       如果遗嘱保留被设置为0,服务端必须将遗嘱消息当作非保留消息发布。
       如果遗嘱保留被设置为1,服务端必须将遗嘱消息当作保留消息发布。
       Bit 6:密码标志位。如果密码(Password)标志被设置为0,有效载荷中不能包含密码字段。如果密码(Password)标志被设置为1,有效载荷中必须包含密码字段。如果用户名标志被设置为0,密码标志也必须设置为0。

       Bit 7:用户名标志位。如果用户名(User Name)标志被设置为0,有效载荷中不能包含用户名字段。如果用户名(User Name)标志被设置为1,有效载荷中必须包含用户名字段。

连接标志位最常见的组合是:1100 0010,即为 0xC2。

  • 保持连接时间(Keep Alive)

       保持连接(Keep Alive)是一个以秒为单位的时间长度,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ报文。

       不管保持连接的值是多少,客户端任何时候都可以发送PINGREQ报文,并且使用PINGRESP报文判断网络和服务端的活动状态。

       如果保持连接的值非零,并且服务端在一点五倍的保持连接时间内没有收到客户端的控制报文,它必须断开客户端的网络连接,认为网络连接已断开。

       客户端发送了PINGREQ报文之后,如果在合理的时间内仍没有收到PINGRESP报文,它应该关闭到服务端的网络连接。

              保持连接的实际值是由应用指定的,一般是几分钟。允许的最大值是18小时12分15秒。

2.1.3 有效载荷

       CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码。

2.2 连接响应(CONNACK)

       服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文必须是CONNACK。

       如果客户端在合理的时间内没有收到服务端的CONNACK报文,客户端应该关闭网络连接。

       CONNACK 没有 有效载荷 字段。

2.2.1 固定报头 

       剩余长度值,表示可变报头的长度。对于CONNACK报文这个值为2。

 2.2.2 可变报头

       当前会话标志位 SP(Session Present):如果服务端收到清理会话(CleanSession)标志为1的连接,除了将CONNACK报文中的返回码设置为0之外,还必须将CONNACK报文中的当前会话设置(Session Present)标志为0。

       如果服务端收到一个CleanSession为0的连接,当前会话标志的值取决于服务端是否已经保存了ClientId对应客户端的会话状态。如果服务端已经保存了会话状态,它必须将CONNACK报文中的当前会话标志设置为1。如果服务端没有已保存的会话状态,它必须将CONNACK报文中的当前会话设置为0。还需要将CONNACK报文中的返回码设置为0。

       如果服务端发送了一个包含非零返回码的CONNACK报文,它必须将当前会话标志设置为0。

       连接返回码:如果服务端收到一个合法的CONNECT报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码的CONNACK报文。

       如果服务端发送了一个包含非零返回码的CONNACK报文,那么它必须关闭网络连接。

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

       CONNACK 没有 有效载荷 字段。

2.3 DISCONNECT - 断开连接

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

2.3.1 固定报头

       CONNACK 没有 可变报头 字段。

       CONNACK 没有 有效载荷 字段。

       客户端发送DISCONNECT报文之后,必须关闭网络连接,并且不能通过这个网络连接再发送任何控制报文。

       服务端在收到DISCONNECT报文时,必须丢弃任何与当前连接关联的未发布的遗嘱消息,并且关闭网络连接(如果客户端 还没关闭连接的话)。

3.订阅

3.1 SUBSCRIBE - 订阅主题报文

       客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给那些订阅匹配的主题,服务端发送PUBLISH报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据这个发送应用消息给客户端。

3.1.1 固定报头

       SUBSCRIBE控制报固定报头的第3,2,1,0位是保留位,必须分别设置为0,0,1,0。服务端必须将其它的任何值都当做是不合法的并关闭网络连接。

       剩余长度字段:等于SUBSCRIBE可变报头的长度(2字节)加上有效载荷的长度。

3.1.2 可变报头

       可变报头包含客户端报文标识符。

       报文标识符相当于自定义的Topic的ID,用ID号去代替具体的Topic,而不是字段,使得区分发来的Topic的同时又可以节省流量,可自定义,建议自己预先拟定一个服务ID表。

       订阅返回,返回Topic订阅成功信息,返回的不是具体Topic,返回的就是报文标识符。

 3.1.3 有效载荷

       SUBSCRIBE报文的有效载荷包含了一个主题过滤器列表,它们表示客户端想要订阅的主题。SUBSCRIBE报文有效载荷中的主题过滤器列表必须是UTF-8字符串。服务端应该支持包含通配符的主题过滤器。如果服务端选择不支持包含通配符的主题过滤器,必须拒绝任何包含通配符过滤器的订阅请求。每一个过滤器后面跟着一个字节,这个字节被叫做 服务质量要求(Requested QoS)。它给出了服务端向客户端发送应用消息所允许的最大QoS等级。

       SUBSCRIBE报文的有效载荷必须包含至少一对主题过滤器 和 QoS等级字段组合。没有有效载荷的SUBSCRIBE报文是违反协议的。
 

       当前版本的协议没有用到服务质量要求(Requested QoS)字节的高六位。如果有效载荷中的任何位是非零值,或者QoS不等于0,1或2,服务端必须认为SUBSCRIBE报文是不合法的并关闭网络连接。

       响应:服务端收到客户端发送的一个SUBSCRIBE报文时,必须使用SUBACK报文响应。

       服务端发送给客户端的SUBACK报文对每一对主题过滤器 和QoS等级都必须包含一个返回码。这个返回码必须表示那个订阅被授予的最大QoS等级,或者表示这个订阅失败。服务端可以授予比订阅者要求的低一些的QoS等级。为响应订阅而发出的消息的有效载荷的QoS必须是原始发布消息的QoS和服务端授予的QoS两者中的最小值。如果原始消息的QoS是1而被授予的最大QoS是0,允许服务端重复发送一个消息的副本给订阅者。

3.2订阅确认(SUBACK)

       服务端发送SUBACK报文给客户端,用于确认它已收到并且正在处理SUBSCRIBE报文。

       SUBACK报文包含一个返回码清单,它们指定了SUBSCRIBE请求的每个订阅被授予的最大QoS等级。

3..2.1 固定报头

 3.2.2 可变报头

       可变报头包含等待确认的SUBSCRIBE报文的报文标识符。

 3.2.3 有效载荷

       有效载荷包含一个返回码清单。每个返回码对应等待确认的SUBSCRIBE报文中的一个主题过滤器。返回码的顺序必须和SUBSCRIBE报文中主题过滤器的顺序相同。

       下面表格描述了有效载荷中单字节编码的返回码字段。

       允许的返回码值:

       0x00 - 最大 Qos0

       0x01 - 成功 - 最大 Qos1

       0x02 - 成功 - 最大 Qos2

       0x80 - Failure 失败

       0x00, 0x01, 0x02, 0x80之外的SUBACK返回码是保留的,不能使用。

3.3取消订阅(UNSUBSCRIBE)

       客户端发送UNSUBSCRIBE报文给服务端,用于取消订阅主题。

3..3.1 固定报头

       UNSUBSCRIBE报文固定报头的第3,2,1,0位是保留位且必须分别设置为0,0,1,0。服务端必须认为任何其它的值都是不合法的并关闭网络连接。

3.3.2 可变报头

       可变报头包含一个报文标识符。

 3.3.3 有效载荷

       UNSUBSCRIBE报文的有效载荷包含客户端想要取消订阅的主题过滤器列表。UNSUBSCRIBE报文中的主题过滤器必须是连续打包的UTF-8编码字符串。

       UNSUBSCRIBE报文的有效载荷必须至少包含一个消息过滤器。没有有效载荷的UNSUBSCRIBE报文是违反协议的。

       UNSUBSCRIBE的有效载荷比SUBSCRIBE少了服务质量要求(Requested QoS)。

       响应:UNSUBSCRIBE报文提供的主题过滤器(无论是否包含通配符)必须与服务端持有的这个客户端的当前主题过滤器集合逐个字符比较。如果有任何过滤器完全匹配,那么它(服务端)自己的订阅将被删除,否则不会有进一步的处理

       如果服务端删除了一个订阅:

       它必须停止分发任何新消息给这个客户端。
       它必须完成分发任何已经开始往客户端发送的QoS 1和QoS 2的消息。
       它可以继续发送任何现存的准备分发给客户端的缓存消息。
       服务端必须发送UNSUBACK报文响应客户端的UNSUBSCRIBE请求。UNSUBACK报文必须包含和UNSUBSCRIBE报文相同的报文标识符 。即使没有删除任何主题订阅,服务端也必须发送一个SUBACK响应。


3.4 取消订阅确认(UNSUBACK)

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

3.4.1 固定报头

       剩余长度字段:表示可变报头的长度,对UNSUBACK报文这个值等于2。

3.4.2 可变报头 

       可变报头包含等待确认的UNSUBSCRIBE报文的报文标识符。

        UNSUBACK报文没有有效载荷。

4.发布

4.1 发布消息(PUBLISH)

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

4.1.1 固定报头

DUP重发标志 

       位置:第1个字节,第3位。

       如果DUP标志被设置为0,表示这是客户端或服务端第一次请求发送这个PUBLISH报文。如果DUP标志被设置为1,表示这可能是一个早前报文请求的重发。

       客户端或服务端请求重发一个PUBLISH报文时,必须将DUP标志设置为1。对于QoS 0的消息,DUP标志必须设置为0。

Qos服务质量等级
       位置:第1个字节,第2-1位。这个字段表示应用消息分发的服务质量等级保证。

        PUBLISH报文不能将QoS所有的位设置为1。如果服务端或客户端收到QoS所有位都为1的              PUBLISH报文,它必须关闭网络连接。

RETAIN保留标志

       位置:第1个字节,第0位。

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

       服务端发送PUBLISH报文给客户端时,如果消息是作为客户端一个新订阅的结果发送,它必须将报文的保留标志设为1。当一个PUBLISH报文发送给客户端是因为匹配一个已建立的订阅时,服务端必须将保留标志设为0,不管它收到的这个消息中保留标志的值是多少。

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

       如果客户端发给服务端的PUBLISH报文的保留标志位0,服务端不能存储这个消息也不能移除或替换任何现存的保留消息。

4.1.2 可变报头

       可变报头按顺序包含主题名和报文标识符。

       主题名(Topic Name)用于识别有效载荷数据应该被发布到哪一个信息通道。

       主题名必须是PUBLISH报文可变报头的第一个字段。它必须是 1.5.3节定义的UTF-8编码的字符串。

       PUBLISH报文中的主题名不能包含通配符。

       服务端发送给订阅客户端的PUBLISH报文的主题名必须匹配该订阅的主题过滤器

       只有当QoS等级是1或2时,报文标识符(Packet Identifier)字段才能出现在PUBLISH报文中。

4.1.3 有效载荷

       有效载荷包含将被发布的应用消息。数据的内容和格式是应用特定的。有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度。包含零长度有效载荷的PUBLISH报文是合法的。

       响应:PUBLISH报文的接收者必须按照根据PUBLISH报文中的QoS等级发送响应。

动作:

  • 客户端使用PUBLISH报文发送应用消息给服务端,目的是分发到其它订阅匹配的客户端。
  • 服务端使用PUBLISH报文发送应用消息给每一个订阅匹配的客户端。

4.2 发布确认( PUBACK)

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

4.2.1 固定报头

        剩余长度字段:表示可变报头的长度。对PUBACK报文这个值等于2。

4.2.2 可变报头

       包含等待确认的PUBLISH报文的报文标识符。

       PUBACK 报文没有有效载荷。

       PUBACK 报文只有 固定报头 和 可变报头,共4个字节。

4.3 发布收到(PUBREC)

       Qos 2,第一步

4.4 发布释放(PUBREL) 

       Qos 2,第二步

4.5 发布收到(PUBCOMP)

       Qos 2,第三步

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值