搞清MQTT协议(二)

各个类型MQTT控制包详细说明

关于MQTT的介绍和控制包格式介绍,请参见上一篇文章。上一篇文章提到,MQTT协议标准中一共有14种类型的控制包,这篇文章就对着14种类型的控制包做一个介绍。

    • CONNECT

如果一个客户端和服务端建立了网络通信,客户端第一个发送给服务端的包就应该是CONNECT。CONNECT在一次网络连接中只发送一次。如果服务器收到了第二个CONNECT,就应该视为协议违反,断开和客户端的连接。

固定头

Bit

7

6

5

4

3

2

1

0

byte 1

MQTT控制包类型 (1)

保留

0

0

0

1

0

0

0

0

byte 2…

剩余长度

变量头

变量头包含了四个部分,按照顺序分为:协议名称,协议登记,连接标志 和保持存活.

协议名称

描述

7

6

5

4

3

2

1

0

协议名称

byte 1

长度值的MSB (0)

0

0

0

0

0

0

0

0

byte 2

长度值的LSB (4,MQTT四位)

0

0

0

0

0

1

0

0

byte 3

‘M’

0

1

0

0

1

1

0

1

byte 4

‘Q’

0

1

0

1

0

0

0

1

byte 5

‘T’

0

1

0

1

0

1

0

0

byte 6

‘T’

0

1

0

1

0

1

0

0

前面两位表示后面还有4位字符,后面4位是MQTT,如果收到的不是MQTT,就不能以MQTT的标准协议来解析下面的数据。

协议等级(版本)

描述

7

6

5

4

3

2

1

0

协议等级

byte 7

等级(4)

0

0

0

0

0

1

0

0

现在使用的是MQTT3.1.1版本,规定等级是4。如果服务端不可接收这个版本,那就需要在CONNACK中回复代码0x01,然后断开和客户端的连接。

连接标志

连接标志包含了一些MQTT连接行为的设置和payload中值存在性。

Bit

7

6

5

4

3

2

1

0

User Name Flag

Password Flag

Will Retain

Will QoS

Will Flag

Clean Session

Reserved

byte 8

X

X

X

X

X

X

X

0

最后一位Reserved也必须为0,如果Server确认最后一位不是零,必须断开连接。

Clean Session
  • 如果被设置成0,服务端必须继续与服务器通信,根据当前会话状态(由服务器标志符定义)。如果当前没会话,就新建一个会话。服务端和客户端在服务器和客户端断开后,必须存储会话。在Clean Session设置为0的会话断开以后,服务端必须存储客户端在断开时的订阅的QoS1和QoS2信息作为会话状态。他可能也存储符合相同标准的QoS 0消息。

  • 如果被设置成1,客户端和服务端必须抛弃之前的会话并且开始一个新会话。这个会话仅在这个网络连接上持续。会话的状态数据在后面的会话中都不能再使用。

客户端会话的状态有两种:

  • QoS1和QoS2已经发送到服务端,不过还没有被完整的响应。

  • 已经从服务端收到QoS2 信息,不过还没有被完整响应

服务端会话的状态有如下几种:

  • 至少存在一个会话(即便其他会话状态都是空的)

  • 客户端的订阅

  • QoS1 和QoS2信息已经被发送到客户端,不过还没有被完整响应

  • QoS1 和 QoS2信息等待传输至客户端

  • QoS2信息已经被客户端接收,不过还没有被完整响应

  • 可选的,QoS0信息等待传输至客户端

注:

  1. 保留信息不组成服务器的会话状态,在会话结束时,不能被删除。

  1. 在Clean Session被设置为1时,客户端和服务器不需要以自动删除会话状态。

  1. 在Clean Session被设置为1时,客户端应该重复尝试连接,直到连接成功。

  1. 一般在一个应用程序下,客户端应该始终用一种Clean Session进行连接,而不是有时0有时1(可能也视应用程序而定)。在Clean Session被设置为1时,客户端将不会收到旧的应用程序消息,而且必须每次都重新订阅。在Clean Session被设置为0时,客户端将接收所有QoS1或QoS2断开连接时发布的消息。因此,如果你要断开连接时不丢失消息,要使用QoS1或QoS2,并且Clean Session要设置为0。

  1. 在Clean Session被设置为0时,则服务器在客户端断开连接后,仍要维护会话状态。客户端如果还要再后面再连接这个服务器,那他应该连接时将Clean Session被设置为0。如果客户端需要永久结束会话,那他需要连接一次服务端,将Clean Session被设置为1,然后断开连接。

Will Flag(遗嘱标志)

在Will Flag设置为1时:如果连接建立,则遗嘱信息必须被存储在服务端,与网络连接关联。如果网络连接关闭,则遗嘱信息必须被发布。除非遗嘱信息在收到一个DISCONNECT包后被删除。

一般遗嘱信息被发布的情况可能包括:

  • 服务器检测到一个IO错误或者网络连接失败

  • 客户端在Keep Alive时间中没有通信

  • 客户端在没有发送DISCONNECT包时就关闭了网络连接

  • 服务器检测到协议错误后关闭了网络连接

在Will Flag设置为1时:连接标志中的Will QoS 和 Will Retain 位置将会被服务器使用,而遗嘱话题和遗嘱信息必须在有效负载中被展示。

如果遗嘱信息被发布或者服务器从客户端接收到一个DISCONNECT包,则它就要在存储的会话状态中被移除。

在Will Flag设置为0时: 连接标志中的Will QoS 和 Will Retain 位置会被设置成0,,而遗嘱话题和遗嘱信息不会在有效负载中被展示,而遗嘱信息也不会在网络连接结束时被发布。

服务器应该及时发布遗嘱信息,但是可能服务器会因为一些故障关机,这样服务器可能会在下一次重启时再发布遗嘱,就会有延误的情况。

Will QoS

占据了两个bit

在发布遗嘱信息时,用于说明QoS的等级。

如果Will Flag被设置为0,那Will QoS也要被设置为00

如果Will Flag被置1,那QoS可以是00,01或10,但是不能是11。

Will Retain

这一位标明了遗嘱信息在发布时是否要被设置为保留。

如果Will Flag被设置为0,那Will Retain也要被设置为0

如果Will Flag被设置为0,有两种情况:

如果Will Retain被设置为0,服务器发布一个非保留的遗嘱信息

如果Will Retain被设置为1,服务器发布一个保留的遗嘱信息

User Name Flag

如果User Name Flag被置1,那user name需要包括在有效负载中。

0就是不包括。

Password Flag

如果Password Flag被置1,那密码需要包括在有效负载中。

0就是不包括。

但是如果User Name Flag设置为0,那Password Flag也要被设为0。

Keep Alive

包括两个字节

Bit

7

6

5

4

3

2

1

0

byte 9

Keep Alive MSB

byte 10

Keep Alive LSB

Keep Alive代表一个时间间隔,最小单位为秒。是一个客户端发送两个控制包之间的最大允许时间(从上一个结束到下一个开始)。客户端必须保证发送两个控制包的时间间隔要小于该值,如果没啥发了,就发送PINGREQ的控制包。

客户端可以在任何时候发送PINGREQ控制包,不管Keep Alive值是多少,而且使用PINGRESP来确定网络或者服务器是否工作。

如果Keep Alive不是0,那服务器在1.5倍Keep Alive时间周期中接收不到客户端的值,他就必须断开和客户端的网络连接(视为网络故障)

如果客户端在发送PINGREQ后一段时间(时间长度可能自定义)内收不到PINGRESP,那他应该对服务器关闭网络连接。

如果Keep Alive被设置为0,那就视为关闭keep alive这个机制。这是,(客户端请求)服务器不能以不活动为理由关闭客户端的连接。当然其实服务器可以主动断开和一个客户端的连接,以任何理由任何时间。

Keep Alive最长可以设置为18小时12分钟15秒。

有效载荷

有效载荷必须按照变量头中的标志位来,而且顺序必须为客户标志符,遗嘱话题,遗嘱信息,User Name, Password。

客户端标志符

就是客户端ID,每一个客户端都要有一个单独的id。

客户端标志符是必须的,并且放在有效载荷的第一个位置。

客户端标志符必须符合UTF-8编码字符串的格式。

服务器必须允许的不超过23,只能包括数字、小写字母和大写字母的客户端标志符长度。

服务器也可以允许长度超过23,包括其他字符的客户端标志符。

服务器甚至可以接受长度为0的客户端标志符,但是如果这样,服务器也应该给这个客户端赋与一个特别的客户端标志符,并且按照这个特殊标志符来处理CONNECT包。

如果客户端提供了一个0位的id,客户端的Clean Session也必须为1。

如果客户端提供了一个0位的id,但是将Clean Session设为0,那服务端必须回复一个CONNACK包,代码为0x02(拒绝id),并且关闭网络连接。其他情况的拒绝id也是同样处理。

注:客户端可能会用随机的方法生成一个标志符。但是当Clean Session为0时,这种方法最好别用。

Will Topic

如果Will Flag被设置为1,那Will Topic就要跟在客户端标志符后面。

必须符合UTF-8编码字符串的格式

Will Message

如果Will Flag被设置为1,那Will Message就要跟在Will Topic后面,这个就是Will Topic相关的信息。

也符合UTF-8编码字符串的格式。但是UTF-8编码前两位是字符串字节的长度,是不发布的。

User Name

如果User Name Flag被置1,就必须包括。

必须符合UTF-8编码字符串的格式,用于授权和认证。

Password

密码可以是不符合UTF-8编码的格式,可以只看内容的二进制码,但是密码内容是不包括前面的两位密码长度。

7

6

5

4

3

2

1

0

字节 1

数据长度 MSB

字节 2

数据长度 LSB

字节 3 ....

数据,如果长度 > 0.

响应

服务器可能支持多种协议,如果服务器是MQTT 3.1.1,按照如下方式验证连接尝试:

  1. 如果服务器在网络连接后的合理时间内未收到CONNECT数据包,则应该关闭连接。

  1. 服务器必须验证CONNECT包遵守本节中的标准,如果不遵守,就直接关闭网络连接,不需要发送CONNACK。

  1. 如果服务器确认CONNECT不符合自己更近一步的要求,或者没有密码或权限验证,它应该发送一个正确的CONNACK,包括一个非零的码,然后关闭网络连接。

如果验证正确,服务器将执行以下步骤:

  1. 如果客户端标志符代表的客户端已经和服务器连接了,服务器必须断开原有连接。

  1. 服务器必须执行之前设置的Clean Session

  1. 服务器必须响应一个CONNACK包,代码为0

  1. 开始信息传输和检测存活

客户端允许在发送CONNECT包以后马上发送其他控制包,不用等到收到CONNACK包。不过如果收到服务端的拒绝,客户端在发送CONNECT包后必须不再发送任何数据。

注:客户端一般是等待CONNACK包的。不等包可能会简化一些客户端实现。不过如果收到服务端的拒绝响应,客户端必须认为,在CONNECT包发送后的其他包,都不会被服务端执行。

    • CONNACK

客户端发送CONNECT包后,服务器发送CONNACK包进行确认。服务端发送给客户端的第一个包必须是CONNACK包。

如果客户端在一定时间内没有收到CONNACK包,客户端应该关闭和服务器的网络连接。这个时间限制可以根据应用自己来定。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (2)

保留

0

0

1

0

0

0

0

0

字节 2

剩余长度 (2)

0

0

0

0

0

0

1

0

对于CONNACK包,剩余长度肯定是2。

变量头

描述

7

6

5

4

3

2

1

0

连接确认标志

保留

SP

字节 1

0

0

0

0

0

0

0

X

连接返回代码

字节 2

X

X

X

X

X

X

X

X

连接响应标志

字节1是连接响应标志符,只用到了第0位(SP),其他位必须设置为0;

SP(Session Present)是会话存在的标志。

会话存在

如果服务端收到的CONNECT的Clean Session设置为1,那服务端必须设置SP为0,并且返回码为0。

如果服务端收到的CONNECT的Clean Session设置为0,那SP的值取决于服务端是否已经为提供的客户端ID存储了会话状态。如果服务端已经存储了会话状态,那SP必须设置为1。如果服务端没有存储会话状态,那必须设置SP为0。同时返回码也要设置为0。

SP标志就是用来在会话是否保存这一问题,统一服务端和客户端的。

如果会话建立完成,保存了会话的客户端也会希望服务端位置保存的会话。如果客户端收到的SP值和预期的不一样,客户端可以决定是否继续会话,或者断开连接。如果客户端连接服务端的时候,设置Clean Session为1,然后再断开连接,那客户端可以丢弃服务端和客户端两端的会话状态。

如果服务端发送了一个CONNACK包,包含的返回码不为0,那服务端必须设置SP为0。

连接返回码

连接返回码是变量头的第二个字节。

如果客户端发送的CONNECT正确,但是服务端因为一些原因不能继续会话,就会发送一个返回码不是0的CONNACK。服务端发送非0返回码的CONNACK以后,必须马上断开网络连接。

返回代码响应

描述

0

0x00,接受连接

接受连接

1

0x01,连接被拒绝,不可接受的协议版本

服务器不支持客户端要求的 MQTT 协议级别

2

0x02,连接被拒绝,标识符被拒绝

客户端标识符是正确的 UTF-8,但服务器不接受

3

0x03,连接被拒绝,服务器不可用

已建立网络连接,但 MQTT 服务不可用

4

0x04,连接被拒绝,用户名或密码错误

用户名或密码中的数据格式不正确

5

0x05,连接被拒绝,未授权

客户端无权连接

6-255

保留供将来使用

如果以上的这些代码都不适用,服务器必须直接关闭网络连接,不发送CONNACK。

有效载荷

CONNACK包没有有效载荷。

    • PUBLISH

PUBLISH是一个双向传输应用消息的控制包。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT控制数据包类型 (3)

DUP标志

QoS级别

RETAIN

0

0

1

1

X

X

X

X

字节 2

剩余长度

DUP

如果DUP标志被设为0,表示这是服务端或客户端第一次尝试发送MQTT的PUBLISH包。如果DUP标志设置为1,表示这可能是之前MQTT的PUBLISH包的重复发送。

如果服务端或者客户端尝试重复发送一个PUBLISH包,DUP标志必须设置为1。如果QoS为0,那所有的DUP标志也要设置为0。

在PUBLSIH包中DUP的标志位不会被服务器传给相关的订阅者。DUP标志在PUBLISH包中是独立的。

注1:如果接收到DUP为1的控制包,不能表示它看到过一个相同的包。

注2:DUP指的是控制包本身,不是控制包中的应用信息。当使用QoS为1是,可能客户端接收到了一个DUP标志位0的PUBLSIH包,但是包含的应用信息是之前收到过的,包ID也不同。

QoS

QoS还是一个很重要的概念。它指代了发送一条应用消息的保证登记。

QoS值

位 2

位 1

描述

0

0

0

最多一次发送

1

0

1

至少一次发送

2

1

0

恰好一次发送

-

1

1

保留 – 不得使用

如果服务端或者客户端收到一条QoS两位都设为1的包,必须立即关闭网络连接。

RETAIN

如果一个客户端发送到服务端中的一个PUBLISH包中RETAIN标志设为1,那服务端必须存储应用信息和QoS,从而控制包可以将消息发送给以后的订阅符合主题名称的订阅者。当一个新的订阅建立,其关注的主题的最后的保留信息将会发送给订阅者。如果服务端接收到一个QoS为0的包,但是RETAIN为1,那他必须丢弃之前这个主题下面的所有信息。他应该存储信息QoS为0的消息,作为主题下新保留的信息,不过可能选择在任何时间下都丢弃掉它(不过这样的话这个主题下就没有保留信息了)。

如果一个消息是作为一个新的订阅的结果,服务端发送一个PUBLISH包到客户端,必须设置RETAIN标志位1。当服务端发送的一个PUBLISH是符合一个已经建立的订阅,则必须设置PUBLISH的RETAIN标志位0。

如果一个PUBLISH包的RETAIN标志为1,有效载荷为空,也可以被服务器正常处理(正常情况下,如果有效载荷为空,RETAIN标志也要为0,消息不会储存),然后发送给客户端一个匹配主题名称的订阅。同时相同主题下,任何存在的保留信息必须被移除,任何未来的订阅者也不会收到该主题的保留信息。

如果保留标志是0,客户端发送给服务器的PUBLISH包中的信息,服务器都不能存储,也不能覆盖或删除任何已经保留的信息。

保留信息在发布者不定期发布状态消息时很有用。一个新的订阅者会收到最近的状态。

变量头

变量头中按顺序包含了主题名称和包标志符两个部分。

主题名称

主题名称标明了有效载荷数据被发布的信息通道。

PUSbLISH包中的不能包含通配符。

服务器发送给订阅服务器的一个PUBLISH包中的主题名称必须匹配订阅的主题过滤器。不过服务端允许重写主题名称,所以服务器发送的包里的主题名称可能和原来PUBLISH中的不一样。

包标志符

包标志符只有在QoS=1或2的PUBLISH包里面有。

有效载荷

有效载荷里面就是应用信息,格式和内容都可以根据应用制定。也可以为长度为0。

响应

接收方接收到一个PUBLISH包后,必须根据QoS响应一个对应的包。

QoS等级

期望响应

QoS 0

QoS 1

PUBACK 包

QoS 2

PUBREC 包

操作

客户端使用PUBLISH包来发送应用消息至服务器,让其发布到匹配订阅的客户端。

服务器使用PUBLISH包发布应用消息到匹配订阅的客户端。

当客户端使用包含通配符的主题过滤器生成订阅时,这样可能一个客户端的订阅会重叠(一个发布的信息可能会匹配多个过滤器)。这种情况下,服务端会发送消息到期望所有匹配当中QoS最大的客户。服务端也可能发送多分复制的信息,每一份信息既匹配订阅也遵循订阅的QoS。

PUBLISH包接收方的操作取决于QoS等级。

如果一个服务端的实现不允许一个客户端发送一个PUBLISH,它也没有方法通知到客户端。它只能按照QoS规则进行积极响应,要不就关闭网络连接。

    • PUBACK

PUBACK是QoS为1时候的PUBLISH包的响应。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (4)

保留

0

1

0

0

0

0

0

0

字节 2

剩余长度 (固定就是2)

0

0

0

0

0

0

1

0

变量头

变量头里面包含了对应PUBLISH包中的包标志符。

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效载荷

操作

详见本系列文章的(三)。

    • PUBREC(收到QoS 2发布,第1部分)

PUBREC包是对一个QoS为2的PUBLISH包的响应。是QoS协议交换是的第二个数据包。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (5)

保留

0

1

0

1

0

0

0

0

字节 2

剩余长度 (固定为2)

0

0

0

0

0

0

1

0

变量头

变量头里面包含了对应PUBLISH包中的包标志符。

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效载荷

操作

详见本系列文章的(三)。

    • PUBREL(收到QoS 2发布,第2部分)

PUBREL 数据包是对 PUBREC 数据包的响应。是的 QoS 2 协议交换的第三个数据包。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (6)

保留

0

1

1

0

0

0

1

0

字节 2

剩余长度 (2)

0

0

0

0

0

0

1

0

变量头

变量头包含与PUBREC 数据包中相同的包标志符。

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效载荷

操作

详见本系列文章的(三)。

    • PUBCOMP(收到QoS 2发布,第三部分)

PUBCOMP 数据包是对 PUBREL 数据包的响应。是的 QoS 2 协议交换的第四个也是最后一个数据包。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (7)

保留

0

1

1

1

0

0

0

0

字节 2

剩余长度 (2)

0

0

0

0

0

0

1

0

变量头

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效载荷

操作

详见本系列文章的(三)。

    • SUBSCRIBE

SUBSCRIBE包是从客户端发到服务端,来创造一个或多个订阅。每个订阅登记了一个客户端感兴趣的话题。服务端发送PUBLSIH包至客户端为了转发匹配相关订阅的信息。SUBSCRIBE包也标明了服务端发送到客户端的最大的QoS。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (8)

保留

1

0

0

0

0

0

1

0

字节 2

剩余长度

变量头

变量标头包含数据包标识符,其他没有了,所以不在此处显示了。

有效载荷

SUBSCRIBE的有效载荷包括了一串客户端想要订阅的主题过滤器。主题过滤器必须符合UTF-8编码字符串的格式要求。一个服务器必须支持包含通配符的主题过滤器。如果服务器选择不支持包含通配符的主题过滤器,那它必须拒绝任何包含通配符的订阅。所有的过滤器后面都必须跟一个字节,叫做请求QoS。这给出了服务器能够发送给客户端的最高QoS等级。

SUBSCRIBE包必须包含至少一个主题过滤器/QoS对,一个SUBSCRIBE包如果不包括有效载荷的话是不符合协议的。

描述

7

6

5

4

3

2

1

0

主题过滤器

字节 1

长度 MSB

字节 2

长度 LSB

字节 3..N

主题过滤器

请求的 QoS

保留

QoS

字节 N+1

0

0

0

0

0

0

X

X

请求的QoS字节高位的6个位目前没有使用。如果这6个为不为0,或者QoS都为1,那服务器必须视为该控制包格式非法,并且关闭网络连接。

有效载荷的例子

描述

7

6

5

4

3

2

1

0

主题过滤器

字节 1

长度 MSB (0)

0

0

0

0

0

0

0

0

字节 2

长度 LSB (3)

0

0

0

0

0

0

1

1

字节 3

“a”(0x61)

0

1

1

0

0

0

0

1

字节 4

“/”(0x2F)

0

0

1

0

1

1

1

1

字节 5

“b”(0x62)

0

1

1

0

0

0

1

0

请求的 QoS

字节 6

请求的 QoS(1)

0

0

0

0

0

0

0

1

主题过滤器

字节 7

长度 MSB (0)

0

0

0

0

0

0

0

0

字节 8

长度 LSB (3)

0

0

0

0

0

0

1

1

字节 9

“c”(0x63)

0

1

1

0

0

0

1

1

字节 10

“/”(0x2F)

0

0

1

0

1

1

1

1

字节 11

“d”(0x64)

0

1

1

0

0

1

0

0

请求的 QoS

字节 12

请求的 QoS(2)

0

0

0

0

0

0

1

0

响应

当服务器收到一个SUBSCRIBE包,服务器必须回复一个SUBACK包。SUBACK包必须和SUBSCRIBE包有相同的包标识符(ID)。

服务器允许在发送SUBACK包以前就开始发送匹配订阅的PUBLISH包。

如果服务器收到一个SUBSRIBE包,包含一个主题过滤器和现有的一个订阅的主题过滤器相同,它也要完整的将新订阅覆盖旧订阅,因为他们的QoS可能不同。任何存在的匹配主题过滤器的保留信息都必须被重发,不过发布流不能被打断。

如果主题过滤器不匹配任何现在的订阅过滤器,那一个新的订阅会生成,所有匹配的保留信息都会被发送。

如果一个服务器接收了一个SUBSCRIBE包,包含多个主题过滤器,那它处理的方式和接收多个SUBCRIBE包是一样的,除了将响应都合并到一个SUBACK包中。

服务器发送的SUBACK包必须对每一个主题过滤器/QoS对都包括一个返回码。这个返回码必须既表明了授权订阅的最大的QoS也能指出订阅的失败。服务器可能授权的最大QoS比订阅者要求低。订阅反馈信息中有效载荷信息的QoS必须是原始发布信息QoS的和服务器授权的最大QoS中的较小值。当原始发布信息的QoS为1,但是保证的最大QoS为0,服务器允许发送重复信息到订阅者。

非规范示例:

如果订阅客户端已获得特定的最大 QoS为1 主题筛选器的授权,然后收到筛选器匹配的 QoS为0的应用程序消息。这意味着客户端消息最多收到一个重复的信息。另一方面,发布到同一主题的 QoS为2的消息 被服务器降级到 QoS为1 传送到客户端,客户端可能会收到消息的副本。

如果订阅客户端已授予最大QoS为0,然后是最初作为 QoS为2 发布的应用程序消息可能会在客户端出其不意的丢失,但服务器不应发送该消息的副本。发布到同一主题的 QoS为1消息可能在传输到该客户端时丢失或重复。

非规范评论:

订阅QoS为2的主题筛选器 等效于说“我想接收匹配此过滤器消息在它们发布时使用的QoS等级”。这意味着发布者负责确定消息可以送达的最大 QoS,但订阅者能够要求服务器降级 QoS到一个更适合它的使用。

    • SUBACK

SUBACK包被服务器用来发送给客户端,确认接收和处理SUBSCRIBE包。

SUBACK包包含了一列返回码,指明了每个订阅中最大的QoS等级。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (9)

保留

1

0

0

1

0

0

0

0

字节 2

剩余长度

变量头

变量头包含了来自SUBSCRIBE包中的数据包标志符

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效载荷

有效载荷中包含了一系列返回码。每个返回码对应SUBSCRIBE包中的一个主题过滤器。SUBACK包中返回码的顺序必须和SUBSCRIBE包中主题过滤器的顺序一致。

7

6

5

4

3

2

1

0

返回代码

字节 1

X

0

0

0

0

0

X

X

允许的返回代码:

0x00 - 成功 - 最大 QoS 0

0x01 - 成功 - 最大 QoS 1

0x02 - 成功 - 最大 QoS 2

0x80 - 失败

其他的代码目前不能使用。

    • UNSUBSCRIBE

客户端发送至服务器,为了从主题当中退订。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (10)

保留(固定)

1

0

1

0

0

0

1

0

字节 2

剩余长度(等于变量标头2个字节的长度加上有效负载的长度)

字节1的后四位是必须这样设置的,其他格式视为不正确,需要关闭网络连接。

变量头

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效负载

UNSUBSCRIBE包中的有效载荷包含了客户端希望退订的主题过滤器。一个UNSUBSCRIBE包的主题过滤器必须符合UTF-8编码字符串。

UNSUBSCRIBE包中的有效负载必须至少包含一个主题过滤器,如果没有包含内容,则会视为违反协议。

描述

7

6

5

4

3

2

1

0

主题过滤器

字节 1

长度 MSB (0)

0

0

0

0

0

0

0

0

字节 2

长度 LSB (3)

0

0

0

0

0

0

1

1

字节 3

“a”(0x61)

0

1

1

0

0

0

0

1

字节 4

“/”(0x2F)

0

0

1

0

1

1

1

1

字节 5

“b”(0x62)

0

1

1

0

0

0

1

0

主题过滤器

字节 6

长度 MSB (0)

0

0

0

0

0

0

0

0

字节 7

长度 LSB (3)

0

0

0

0

0

0

1

1

字节 8

“c”(0x63)

0

1

1

0

0

0

1

1

字节 9

“/”(0x2F)

0

0

1

0

1

1

1

1

字节 10

“d”(0x64)

0

1

1

0

0

1

0

0

和SUBSCRIBE包的有效载荷不一样,没有请求的QoS字节。

响应

服务器在收到UNSUBSCRIBE包后,不管主题过滤器中有没有通配符,都必须和主题过滤器组一个字符一个字符的比较。如果任何过滤器准确匹配,那么它的订阅就会被删除,否则不会做其他处理。

如果一个服务器删除一个订阅:

  • 它必须停止发送给原订阅客户端新的信息。

  • 它必须完成已经开始发送了的QoS为1和QoS为2的消息。

  • 它可以发送给客户端已经存在的缓存信息。

服务器必须发送一个UNSUBACK包来响应UNSUBSCRIBE请求。UNSUBACK包的数据包标识符必须和UNSUBSCRIBE包一致。就算没有任何订阅主题被删除(不代表没有payload,有可能是payload中的内容没有匹配上),服务端也要送一个UNSUBACK。

如果一个服务器收到一个包括了多个主题过滤器的UNSUBSCRIBE包,那它处理的方式和接收多个UNSUBCRIBE包是一样的,除了将响应都合并到一个UNSUBACK包中。

    • UNSUBACK

UNSUBACK包由服务端发送给客户端,用来确认接收到一个UNSUBSCRIBE包。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (11)

保留

1

0

1

1

0

0

0

0

字节 2

剩余长度 (固定为2)

0

0

0

0

0

0

1

0

变量头

7

6

5

4

3

2

1

0

字节 1

数据包标识符 MSB

字节 2

数据包标识符 LSB

有效负载

    • PINGREQ

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (12)

保留

1

1

0

0

0

0

0

0

字节 2

剩余长度 (0)

0

0

0

0

0

0

0

0

变量头

有效负载

响应

服务器必须发送PINGRESP数据包来响应客户端发送的PINREQ数据包。

    • PINGRESP

PINGRESP 数据包由服务器发送到客户端 对 PINGREQ 数据包的响应,它指示服务器处于活动状态。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (13)

保留

1

1

0

1

0

0

0

0

字节 2

剩余长度 (0)

0

0

0

0

0

0

0

0

变量头

有效负载

    • DISCONNECT

DISCONNECT数据包是客户端发送给服务器的最后一个控制包。它标明了客户端已经完全断开连接。

固定头

7

6

5

4

3

2

1

0

字节 1

MQTT 控制数据包 类型 (14)

保留

1

1

1

0

0

0

0

0

字节 2

剩余长度 (0)

0

0

0

0

0

0

0

0

变量头

有效负载

响应

客户端在发送了一个DISCONNECT包以后:

  • 必须关闭网络连接

  • 必须不能再发送任何控制包

服务器在收到DISCONNECT包以后:

  • 必须丢弃任何和当前连接有关的遗嘱信息,不能发送。

  • 就算客户端没有关闭网络连接,也应该关闭网络连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值