MQTT 3.1.1 规范

本文很多是意译。如发现模棱两可的地方请看原文(原文十有八九也模棱两可)。
原文:http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

几个重要的特性浓缩在了这篇文章中:
https://blog.csdn.net/mrpre/article/details/82531992

2 MQTT Control Packet format

1.2 Structure of an MQTT Control Packet

MQTT协议靠交换不用的控制帧来工作,这节描述了这些帧的格式。
一个MQTT控制帧总是有3部分组成,如图2.1

 ----------------------------------
|Fixed header, 所有帧都携带       |
 ----------------------------------
|Variable header,某些帧中存在     |
 ----------------------------------
|Payload, 某些帧中存在            |
 ----------------------------------

2.2 Fixed header

每个MQTT控制帧总是包含固定头,如图2.2所示

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  | MQTT Control Packet type  | Flags specific to each MQTT Control Packet type   |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                   Remaining Length                            |
 ---------------------------------------------------------------------------------------------

2.2.1 MQTT Control Packet type

 --------------------------------------------------------------------------------
|  Name      |  Value |  Direction of flow |             Description               |
 --------------------------------------------------------------------------------
| Reserved   |   0    |      Forbidden     |             Reserved                  |
 ---------------------------------------------------------------------------------
| CONNECT    |   1    |  Client to Server  |  Client request to connect to Server  |
 ---------------------------------------------------------------------------------
| CONNACK    |   2    | Server to Client   |  Connect acknowledgment               |
 ---------------------------------------------------------------------------------
| PUBLISH    |   3    |  Client to Server  |  Publish message                      |
|            |        |        or          |                                       |
|            |        |  Server to Client  |                                       |
 ---------------------------------------------------------------------------------
| PUBACK     |   4    |  Client to Server  |  Publish acknowledgment               |
|            |        |        or          |                                       |
|            |        |  Server to Client  |                                       |
 ---------------------------------------------------------------------------------
| PUBREC     |   5    |  Client to Server  |  Publish received (assured delivery   |
|            |        |        or          |  part 1)                              |
|            |        |  Server to Client  |                                       |
 ---------------------------------------------------------------------------------
| PUBREL     |   6    |  Client to Server  |  Publish release  (assured delivery   |
|            |        |        or          |  part 2)                              |
|            |        |  Server to Client  |                                       |
 ---------------------------------------------------------------------------------
| PUBCOMP    |   7    |  Client to Server  |  Publish complete (assured delivery   |
|            |        |        or          |  part 3)                              |
|            |        |  Server to Client  |                                       |
 ---------------------------------------------------------------------------------
|SUBSCRIBE   |   8    |  Client to Server  |  Client subscribe request             |
 ---------------------------------------------------------------------------------
|SUBACK      |   9    |  Server to Client  |  Subscribe acknowledgment             |
 ---------------------------------------------------------------------------------
|UNSUBSCRIBE |   10   |  Client to Server  |  Unsubscribe request                  |
 ---------------------------------------------------------------------------------
|UNSUBACK    |   11   |  Server to Client  |  Unsubscribe acknowledgment           |
 ---------------------------------------------------------------------------------
|PINGREQ     |   12   |  Client to Server  |  PING reques                          |
 ---------------------------------------------------------------------------------
|PINGRESP    |   13   |  Server to Client  |  PONG reques                          |
 ---------------------------------------------------------------------------------
|DISCONNECT  |   14   |  Client to Server  |  Client is disconnecting              |
 ---------------------------------------------------------------------------------
|Reserved    |   15   |  Forbidden         |  Reserved                             |
 ---------------------------------------------------------------------------------

2.2.2 Flags

固定头首个字节的低4比特,包括了一个flag,flag的值对于不同的控制帧而言有不同的含义。如下图。如果flag是Reserved,表示flag含义未定义,目前必须表示为图中的值。如果收到一个非法的flag,接受者必须关闭网络连接。

 -----------------------------------------------------------------------
|  Packet    |  Flags         |   bit 3  |  bit 2  |  bit 1  |  bit 0   |
 -----------------------------------------------------------------------
| PUBLISH    |  Used in MQTT  |          |         |         |          |
|            |      3.1.1     |   DUP    |   QOS   | QOS     |  RETAIN  |
|            |                |          |         |         |          |
 ------------------------------------------------------------------------
|  PUBREL    |  Reserved      |     0    |     0   |    1    |     0    |
 -----------------------------------------------------------------------
|  SUBSCRIBE |  Reserved      |     0    |     0   |    1    |     0    |
 -----------------------------------------------------------------------
|UNSUBSCRIBE |  Reserved      |     0    |     0   |    1    |     0    |
 -----------------------------------------------------------------------
|   Others   |  Reserved      |     0    |     0   |    1    |     0    |
 -----------------------------------------------------------------------

DUP`Qos\RETAIN`详见3.3.1节。

2.2.3 Remaining Length

2个字节
Remaining Length表示当前包剩余的数据的字节,包括可变头和负载。Remaining Length不包括表示Remaining Length自己的那2个字节。
Remaining Length用可变长度字节的方法表示,0-127字节,用1个字节表示。超过此字节的,将当前字节的最高位置1,然后剩余比特以及下一个字节的低7比特表示长度。

 ------------------------------------------------------------------------------------
| Gigit  |            from                  |             to                         |
 ------------------------------------------------------------------------------------
|   1    |       0(0x00)                    |            127(0x7f)                   |
 ------------------------------------------------------------------------------------
|   2    |       128 (0x80, 0x01)           |            16 383 (0xFF, 0x7F)         |
 ------------------------------------------------------------------------------------
|   3    |   16 384 (0x80, 0x80, 0x01)      |    2 097 151 (0xFF, 0xFF, 0x7F)        |
 ------------------------------------------------------------------------------------
|   4    |2 097 152 (0x80, 0x80, 0x80, 0x01)|    268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)|
 ------------------------------------------------------------------------------------

2.3 Variable header

某些类型的MQTT控制帧包括了可变头。它处于固定头和负载之间。不同的控制帧,其可变头不一样。Packet Identifier是比较常见的的可变头。

2.3.1 Packet Identifier

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |                          Packet Identifier MSB                                |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                          Packet Identifier LSB                                |
 ---------------------------------------------------------------------------------------------

许多控制帧包含2字节的Packet Identifier,例如,如下帧会包含Packet IdentifierPUBLISH (where QoS > 0)PUBACKPUBRECPUBRELPUBCOMPSUBSCRIBESUBACKUNSUBSCRIBEUNSUBACK
SUBSCRIBEUNSUBSCRIBE,PUBLISH(QoS > 0)必须包含非0的Packet Identifier,每次client发送一个新的这类的帧,它必须使用一个未使用的Packet Identifier,如果一个client重发一个特定的帧,它必须使用相同的Packet Identifier。对应帧的确认帧收到后,对应的Packet Identifier可以再次被使用。在QOS 1的情况下,PUBLISH的确认帧指的是PUBACK,QOS 2的情况下是PUBCOMP。对于SUBSCRIBEUNSUBSCRIBE,其确认帧是SUBACKUNSUBACK`。 上面的场景,同样适用于server。

QOS 0的PUBLISH帧必须不能包含Packet Identifier
PUBACK PUBREC PUBREL必须使用和其对应的PUBLISH帧的Packet Identifier。类似的,SUBACK``UNSUBACK必须包含对应的SUBSCRIBEUNSUBSCRIBE对应的Packet Identifier

总结就是:

扫描二维码关注公众号,回复: 3242340 查看本文章
---------------------------------------------
|Control Packet  |  Packet Identifier field  |
---------------------------------------------
|CONNECT         |   NO                      |
---------------------------------------------
|CONNACK         |   YES (If QoS > 0)        |
---------------------------------------------
|PUBLISH         |   YES                     |
---------------------------------------------
|PUBACK          |   YES                     |
---------------------------------------------
|PUBREC          |   YES                     |
---------------------------------------------
|PUBREL          |   YES                     |
---------------------------------------------
|PUBCOMP         |   YES                     |
---------------------------------------------
|SUBSCRIBE       |   YES                     |
---------------------------------------------
|SUBACK          |   YES                     |
---------------------------------------------
|UNSUBSCRIBE     |   YES                     |
---------------------------------------------
|UNSUBACK        |   YES                     |
---------------------------------------------
|PINGREQ         |   NO                      |
---------------------------------------------
|PINGRESP        |   NO                      |
---------------------------------------------
|DISCONNECT      |   NO                      |
---------------------------------------------

Client和Server独立的使用Packet Identifier,也就是说Client和Server可能同时使用相同的Packet Identifier进行交换。

   Client                     Server

   PUBLISH Packet Identifier=0x1234--->

   <--PUBLISH Packet Identifier=0x1234

   PUBACK Packet Identifier=0x1234--->

   <--PUBACK Packet Identifier=0x1234

2.4 Payload

一些 MQTT 控制帧在帧的最后包含负载,见下图。

---------------------------------------------
|Control Packet  |     Payload               |
---------------------------------------------
|CONNECT         |   Required                |
---------------------------------------------
|CONNACK         |   None                    |
---------------------------------------------
|PUBLISH         |   Optional                |
---------------------------------------------
|PUBACK          |   None                    |
---------------------------------------------
|PUBREC          |   None                    |
---------------------------------------------
|PUBREL          |   None                    |
---------------------------------------------
|PUBCOMP         |   None                    |
---------------------------------------------
|SUBSCRIBE       |   Required                |
---------------------------------------------
|SUBACK          |   Required                |
---------------------------------------------
|UNSUBSCRIBE     |   Required                |
---------------------------------------------
|UNSUBACK        |   None                    |
---------------------------------------------
|PINGREQ         |   None                    |
---------------------------------------------
|PINGRESP        |   None                    |
---------------------------------------------
|DISCONNECT      |   None                    |
---------------------------------------------

MQTT Control Packets

3.1 CONNECT – Client requests a connection to a Server

一个TCP连接上,一个Client只被允许发送一个CONNECT帧。Server收到第二个CONNECT必须断开连接。4.8节描述了如何处理异常情况。
payload包含了一个或者多个数据。它们决定了Will topicWill Message,用户名,密码。这些都是可选的,是否出现取决于可变头的flags字段。

3.1.1 Fixed header

Remaining Length是10字节的可变头加上负载的大小。

3.1.2 Variable header

CONNECT的可变头包括了4部分Protocol NameProtocol LevelConnect FlagsKeep Alive

3.1.2.1 Protocol Name

6字节。前2字节表示Protocol Name长度,后4字节表示Protocol Name本身。

3.1.2.2 Protocol Level

1字节。就是版本号,3.1是0x3,3.1.1是0x4.

3.1.2.3 Connect Flags

 -----------------------------------------------------------------------------------------------------------------------
|    bit     |    7          |    6        |    5        |    4         |    3      |    2     |    1        |    0    |
 -----------------------------------------------------------------------------------------------------------------------
|    bit     |User Name Flag |Password Flag|Will Retain  | Will Retain  | Will QoS  |Will Flag |Clean Session|Reserved |
 -----------------------------------------------------------------------------------------------------------------------
|    bit     |      X        |     X       |     X       |     X        |     X     |     X    |     X       |    0    |
 -----------------------------------------------------------------------------------------------------------------------
3.1.2.4 Clean Session

Connect Flags的第1个bit。

Client和Server可以保存会话的状态(订阅信息等),这个标志位表示了会话是否长期有效。如果CleanSession为0,Server必须使用保存的该会话的状态(靠username等客户端标识查找session)。如果Server没有查找到对应的session,Server必须创建新的session。client和server断开之后,两端必须保存当前的session。如果CleanSession为0的会话断开了,Server必须保存QOS 1、QOS 2信息。
如果CleanSession为1,client和server必须丢弃老的session并且新建一个。这个session的生命周期是TCP连接的生命周期,这个session在之后的连接上不能被使用。

Client的session信息包括:
1、QOS 1、QOS 2下,发送给了Server但是还未被ACK。
2、QOS 2下,从Server收到了,但是还未给Server ACK。

Server的session信息包括:
1、session是否存在。
2、客户端的订阅。
3、QOS 1、QOS 2下,发送给了Client但是还未被ACK。
4、QOS 1、QOS 2下,等待发送给Client。
5、QOS 2下,从Client收到了,但是还未给Client ACK。
6、QOS 0的情况下,等待发送给Client。(可选)

有retain标志的的消息,不能保存在Session中。

3.1.2.5 Will Flag

Connect Flags的第2个bit。

如果Will Flag为1,则表示Server需要保存Will Message在当前的tcp会话上。在TCP关闭时,Will Message必须被publish到server,除非 Server收到DISCONNECT后会删除Will Message,TCP断开的时候不需要Publish这个message。

需要Publish Will Message的情况如下但不限如下:
1、IO错误或者网络传输失败
2、Keeplaive时间超时
3、Client直接断开TCP连接而没有发送DISCONNECT
4、Server对消息处理错误

如果 Will Flag 被置为1,则Will QoS 和 Will Retain field也会被Server处理,Will Topic 和 Will Message必须存在。
当该Topic+Message已经被Publish后或者Server收到DISCONNECT后,Will Message 会被删除。
如果 Will Flag 被置为0,Will QoS 和 Will Retain field必须是0,Will Topic 和 Will Message。
如果 Will Flag 被置为0,当TCP连接断开后,Will Message不会被Publish。

Server必须立刻Publish Will Message。但是当Server关闭或者错误发送,Will Message可能被推迟Publish指导重启完成才会Publish。

3.1.2.6 Will QoS

Connect Flags的第3、4个bit。
表示 Will Message 的QOS级别。
如果 Will Flag 被置为0,Will QoS必须为0。
如果 Will Flag 被置为1,Will QoS可以为0,1,2,不能为3。

3.1.2.7 Will Retain

Connect Flags的第5个bit。

确定 Will Message 是否需要被保持住。
如果 Will Flag 被置为0,Will Retain必须为0。
如果 Will Flag 被置为1
(1):如果 Will Retain 为0,Will Message 必须当做非retained 的 message。
(2):如果 Will Retain 为1,Will Message 必须当做retained 的 message。

3.1.2.8 User Name Flag

Connect Flags的第7个bit。

如果 User Name Flag 是0,user name不能出现在负载中。
如果 User Name Flag 是1,user name必须出现在负载中。

3.1.2.9 Password Flag

如果 Password Flag 是0,password不能出现在负载中。
如果 Password Flag 是1,password必须出现在负载中。
如果 User Name Flag 是0, Password Flag 是0也必须为0。

3.1.2.10 Keep Alive
 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 9  |                          Keep Alive MSB                                       |
 ---------------------------------------------------------------------------------------------
|    byte 10  |                         Keep Alive LSB                                       |
 ---------------------------------------------------------------------------------------------

Keep Alive的单位是秒,它决定了客户端两个帧之间最大的间隔。客户端有责任保证两个控制帧的发送间隔不超过Keep Alive时间。如果客户端没有要发送的帧时(处于idle状态),客户端必须发送PINGREQ 帧。
客户端可以在任意时刻发送PINGREQ ,及时没到Keep Alive的时间,因为客户端可以用PINGREQ来探测Server服务是否正常。
如果 Keep Alive 时间非0,如果server在1.5倍的Keep Alive时间内没有收到控制帧,Server需要断开和Client的TCP连接。
如果client在一定时间内没有收到对PINGREQ的回复(PINGRESP ),client需要和server断开tcp连接。
Keep Alive时间为0,表示关闭 Keep Alive功能,换句话说,当一定时间内没有帧交互时,Server可以不和客户端断开。
注意:Server可以忽略client提供的Keep Alive,在Server认为连接不活跃的任何时候关闭和client的连接。
Keep Alive 的时间是应用程序定义的,通常几分钟,最长18h12m15s。

3.1.3 Payload

CONNECT帧的payload包括一个或者多个由长度标识的域,这些域是否存在由CONNECT帧中可变头的flags决定,但是顺序必然是如下的:Client Identifier, Will Topic, Will Message, User Name, Password

3.1.3.1 Client Identifier

ClientId 用来标识唯一的一个客户端。client必须携带ClientId,这样Server可以找到对应的会话信息。

client必须携带ClientId,且必须在payload的首个位置。
ClientId必须是 UTF-8 格式的。
1-23字节的UTF-8 格式的ClientId,且每个字节均是如下字符:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,Server必须接受。
Server 可以允许 ClientId 超过23字节,Server允许ClientId不在上面的字符串列表中。
Server 可以允许 Client 提供 0 长度字节的 ClientId, 如果真是这样,Server需要为其分配一个唯一的Clientid,且后续处理流程也和有ClientId一样。
如果Client提供的ClientId长度是0,则 CleanSession 标志位 必须为1。
如果Client提供的ClientId长度是0, 且 CleanSession 标志位为0,则Server的回复的CONNACK的返回码是0x02,表示拒绝id,然后关闭TCP连接。
如果Server拒绝ClientId,它必须回复包含状态码0x02CONNACK 帧。

3.1.3.2 Will Topic

如果Will Flag 是1,则Will Topic将出现在接下来的payload中,Will Topic必须是UTF-8格式。

3.1.3.3 Will Message

如果Will Flag 是1,则Will Message将出现在接下来的payload中,该消息表示应用程序自己将要Publish到server的消息。Will Message有2个字节的长度表示,该长度决定了后面的message内容。该2字节的表示的长度,不包含该2字节本身。
Will Message被Pubslish到Will Topic的时候,其负载不包含该2个字节。

3.1.3.4 User Name

如果 User Name 标志位为1,则负载的下一个部分是User Name,User Name必须是UTF-8格式。

3.1.3.5 Password

如果 Password Flag 标志位 为1,则负载的下一个部分是Password Flag 。Password 域由2字节的长度表示,其余是2字节表示的长度的实际Password。

3.1.4 Response

注意,Server支持多个协议(MQTT的多个版本),如果Server决定使用 MQTT 3.1.1, 则必须进行如下校验:
1:如果在传输层建立完成后的一定时间内没收收到 CONNECT帧,则Server需要关闭连接。
2:如果Server解析CONNECT的格式不对,则必须关闭传输层连接,且不发送CONNACK帧。
3:Server可以解进行其他的校验,例如鉴权等,如果是这些校验出错,Server必须回复CONNECT,且其返回码为非0。

如果Server处理CONNECT成功,则需要进行接下去的几步:
1:如果Clientid表示的的Client已经存在,则必须踢掉当前已经存在的那条连接。
2:Server必须处理 CleanSession 。
3:Server必须回复CONNACK,且状态码为0.
4:开始帧的传输,并且开启keep alive 检测。

Client允许在CONNECT之后立刻发送其他帧,Client无需等待CONNACK帧。如果Server拒绝CONNECT,则Server不能处理任何该Client发送的帧。

3.2 CONNACK – Acknowledge connection request

CONNACK帧的固定头的Remaining Length一直是2 。

3.2.2 Variable header

-----------------------------------------------------------------------------------------------------------------------------
|                 |    Description            |   7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
-----------------------------------------------------------------------------------------------------------------------------
| Connect Acknowledge Flags                   |  Reserved                                                          |    SP   |
 -----------------------------------------------------------------------------------------------------------------------------
|    byte1        |                           |   0    |    0    |    0    |    0    |    0    |    0    |    0    |    x    |
 -----------------------------------------------------------------------------------------------------------------------------
| Connect Return code                         |  Reserved                                                                    |
 -----------------------------------------------------------------------------------------------------------------------------
|    byte2        |                           |   x    |    x    |    x    |    x    |    x    |    x    |    x    |    x    |
 -----------------------------------------------------------------------------------------------------------------------------

byte1 的 1-7bit是保留位,必须为0.
byte1 的低0bit是表示 Session Present。

3.2.2.2 Session Present

如果Server接受CleanSession 为1的请求,Server的CONNACK必须将Session Present 置为0,且CONNACK状态码为0。
如果Server接受CleanSession 为0的请求,Session Present 的值依据Server是否已经保存了对应Clientid的session。如果Server保存了,则Session Present 置为1,反之置为0.除此之外CONNACK状态码为0。
Session Present 标志位能够同步Client和Server之间对于是否存在session的的判断。

一旦连接建立起来,保存session的Client是希望Server也保存session,当收到Session Present 为0的CONNACK,如果这不是Client期望的,Client可以选择是继续执行还是关闭。客户端可以使用如下操作:首先关闭连接,用Clean Session为1的CONNECT发起连接,然后再次关闭连接。

如果Server发送CONNACK包含了非0的状态码,那么Session Present 必须置为0.

3.2.2.3 Connect Return code

可变头中的2个字节。

如果Server收到格式正确的CONNECT帧,但是由于某些原因不能接受,则返回非0的状态码。返回非0的状态码后,Server必须关闭传输层连接。

----------------------------------------------------------------------
|Value  |  Return Code Response           |    Description           | 
----------------------------------------------------------------------
|0      |   Accepted                      |   连接被接受             |
----------------------------------------------------------------------
|1      |  unacceptable protocol version  |   Server不支持请求的协议 |
----------------------------------------------------------------------
|2      |   identifier rejected           |   Clientid不被接受       |
----------------------------------------------------------------------
|3      |   Server unavailable            |   Server未提供服务       |
----------------------------------------------------------------------
|4      |  bad user name or password      |   用户名密码格式错误     |
----------------------------------------------------------------------
|5      |   not authorized                |   客户端未认证           |
----------------------------------------------------------------------
|6-255  |                                 |    保留                  |
----------------------------------------------------------------------

如果Server认为上面的返回码不合适,则直接断开连接而不回复CONNACK

3.2.3 Payload

CONNACK帧没有payload.

3.3 PUBLISH – Publish message

PUBLISH帧被用来从Client到Server或者从Server到Client传输引用消息。

3.3.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (3)     |  DUP    |    QoS level      |  RETAIN |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    1    |    1    |    x    |    x    |    x    |    x    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                   Remaining Length                            |
 ---------------------------------------------------------------------------------------------
3.3.1.1 DUP

如果DUP标志位为0,表示这个第一个Client或者Server发送的的帧,如果DUP标志位为1,表示这可能是重传的上一个帧。
如果Client或者Server想重传帧,则DUP标志位必须置为1,QoS 0的message,所有的DUP都必须为0.
PUBLISH的DUP标志位不会被透传到订阅者那里。发出去的PUBLISH帧和收到的PUBLISH各自的DUP处理是独立的。

收到 DUP 为1的控制帧,不能认为他是之前发送过的帧。

3.3.1.2 Qos

决定了PUBLISH传输的Qos等级。

-------------------------------------------------------------------
|QoS  Value  |  Bit 2   |   Bit 1      |     Description           |
-------------------------------------------------------------------
|0           |   0      |     0        |   At most once delivery   |
-------------------------------------------------------------------
|1           |   0      |     1        |   At least once delivery  |
-------------------------------------------------------------------
|2           |   1      |     0        |   Exactly once delivery   |
-------------------------------------------------------------------
|-           |   1      |     1        |Reserved – must not be used|
-------------------------------------------------------------------

PUBLISH帧不允许两个bit都设置为1,如果Server或者Client收到这样的帧,必须关闭连接。

3.3.1.3 RETAIN

如果 RETAIN标志位是1,Server必须存储PUBLISH的消息以及对应的Qos,这样就能够在后续有人订阅该消息时,直接推送给订阅者。

当一个新的订阅者过来订阅时,和该订阅的topic匹配的最新带有RETAINPUBLISH消息必须被推送给该订阅者。

如果Server收到Qos是0且带有RETAIN标志位的消息topic,则Server必须丢弃任何之前RETAIN消息(匹配该topic的)。Server需要保存这个新的Qos为0的消息为最新的RETAINPUBLISH,Server也可以随时丢弃该QOS为0的消息,这意味着丢弃后,Server就没有该topic对于的RETAIN标志位是1的消息了。

如果Server收到携带RETAIN标志位但是负载是0 的PUBLISH,则Server会删除所有该Topic对应的RETAIN消息,包括该消息本身也不会被保存。

当Server给Client发送Publish的时候,如果topic命中了已保存的带有RETAINPUBLISH消息,则PUBLISH消息的RETAIN标志位设置为1;否则RETAIN标志位设置为0,无论这个PUBLISH是否携带RETAIN标志位。

如果Client发送给Server的RETAIN为0的PUBLISH消息,Server不能保存该消息,并且不能删除当前保存的PUBLISH消息。

3.3.2 Variable header

可变头包含如下几个部分:Topic Name, Packet Identifier。

3.3.2.1 Topic Name

指定了推送消息的Topic。
Topic name必须在可变头的第一个部分,且是UTF8格式的数据。
Topic name不能包含通配符。
PUBLISH的Topic name必须和订阅者订阅条件一致(见4.7)
由于Server允许覆盖Topic Name,Server发送的Topic name和原始收到的Topic name 可能不一样。

3.3.2.2 Packet Identifier

Packet Identifier 只有在 QoS 1或者2的情况下的PUBLISH中才会携带。

3.3.2.3 Variable header non normative example

3.3.3 Payload

包含了PUBLISH的消息。其中的格式是应用层定义的。其长度可以由Remaining Length减去Variable header的长度来获得。PUBLISH消息允许包含空的message。

3.3.4 Response

收到PUBLISH帧的接受者必须根据表3.4中指定的进行回复

------------------------------------------
|QoS Level     |     Expected Respon     |
------------------------------------------
|QoS 0         |   None                  |
------------------------------------------
|QoS 1         |   PUBACK Packet         |
------------------------------------------
|QoS 2         |   PUBREC Packet         |
------------------------------------------

3.3.5 Actions

Client使用PUBLISH消息发送应用消息给Server,Server分发给匹配订阅的Client。
Server使用PUBLISH消息发送应用消息给匹配订阅的Client。

Client订阅的topic可以包含通配符,客户端的的订阅可能有重叠的部分,所以一个PUBLISH可能会匹配多个Topic,Server必须针对每个Qos,发送PUBLISH。In addition, the Server MAY deliver further copies of the message, one for each additional matching subscription and respecting the subscription’s QoS in each case。
接收方收到PUBLISH的行为根据Qos决定,具体参考4.3节。
如果Server对于Client的PUBLISH认证不通过,目前没有办法通知客户端,要么根据Qos回复正常的ACk,要么断开连接。

3.4 PUBACK – Publish acknowledgement

3.4.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (4)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    0    |    1    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length(2)                           |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Remaining Length field
指示了可变头的长度,PUBACK消息是2。

3.4.2 Variable header

包含了 自己ACK的PUBLISH帧的Packet Identifier

3.4.3 Payload

PUBACK没有payload

3.4.4 Actions

见 4.3.2节。

3.5 PUBREC – Publish received (QoS 2 publish received, part 1)

Qos为2的情况下,PUBREC用来回复PUBLISH,他是QoS 2质量下的第二个包。

3.5.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (5)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    0    |    1    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length(2)                           |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Remaining Length field
可变头的长度,对于PUBREC来说是2。

3.5.2 Variable header

包含了 自己ACK的PUBLISH帧的Packet Identifier

3.5.3 Payload

3.5.4 Actions

见 4.3.3

3.6 PUBREL – Publish release (QoS 2 publish received, part 2)

PUBREC帧的回复,这是QoS 2质量下的第三个帧。

3.6.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (6)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    0    |    1    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length(2)                           |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Bit 3,2,1 and 0必须设置为 0 0 1 0 ,Server收到其他形式的PUBREL必须认为是格式错误。

Remaining Length field
可变头的长度,对于PUBREL帧是2字节。

3.6.2 Variable header

可变头包含了和PUBREC一样的Packet Identifier

3.6.3 Payload

3.6.4 Actions

见4.3.3节

3.7 PUBCOMP – Publish complete (QoS 2 publish received, part 3)

是对PUBREL帧的回复,是Qos 2质量情况下的第四个帧以及最后一个帧。

3.7.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (7)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    0    |    1    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length(2)                           |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Remaining Length field
可变头的长度,对于PUBCOMP帧是2字节。

3.7.2 Variable header

可变头包含了和PUBREL一样的Packet Identifier

3.7.3 Payload

3.7.4 Actions

见4.3.3

3.8 SUBSCRIBE - Subscribe to topics

SUBSCRIBE是从Client发送到Server的,用来创建一个或者多个订阅。每个订阅请求包含了Client的一个或者多个感兴趣的topic。Server收到PUBLISH之后,会给匹配topic订阅的客户端发送PUBLISHSUBSCRIBE同时指定了对于当前订阅消息的的最大Qos。

3.8.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (8)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    0    |    1    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length(2)                           |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Bits 3,2,1 and 0必须设置为0 0 1 0,对于其他形式的,Server必须认为是格式错误,并且关闭连接。

Remaining Length field
可变头长度(2字节)加上负载长度

3.8.2 Variable header

可变头包含了Packet Identifier,2.3.1 节提供了更多的信息。

3.8.3 Payload

SUBSCRIBE帧的负载包含了Client想要订阅的Topic列表。Topic必须是UTF-8格式数据,Server应该Topic包含通配符的情况(4.7.1节)。如果Server选择不支持通配符的Topic,则需要拒绝任何包含通配符的Topic。每个Topic包含一个叫做Requested QoS的1字节值,它指定了Client支持的最大的Qos。

SUBSCRIBE必须包含至少一个Topoc+Qos组合,否则任务是protocol violation,4.8节定义了如何处理错误。
每个Qos跟在其Topic之后,每个Topic+Qos都是连续的排列。

表3.2.2

 ----------------------------------------------------------------------------------------------------
|    Description     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ----------------------------------------------------------------------------------------------------
|   Topic Filter                                                                                     |
 ----------------------------------------------------------------------------------------------------
|    byte 1          |                                 Length MSB                                    |
 ----------------------------------------------------------------------------------------------------
|    byte 2          |                                 Length LSB                                    |
 ----------------------------------------------------------------------------------------------------
|bytes 3..N          |                                 Topic Filter                                  |
 ----------------------------------------------------------------------------------------------------
|  Request Qos                                                                                       |
 ----------------------------------------------------------------------------------------------------
|                    |                 Reserved                                  |      Qos          |
 ----------------------------------------------------------------------------------------------------
| byte N+1           |    0    |    0    |    0    |    0    |    0    |    0    |    X    |    X    |
 ----------------------------------------------------------------------------------------------------

Requested QoS的前6个bit在当前协议中没有被用到,给未来的特性用。当前6bit不是这样的情况或者Qos不是 0或1或2,Server必须认为这个是格式错误且关闭连接。

3.8.3.1 Payload non normative example
---------------------------------
|Topic Name     |     “a/b”     |
---------------------------------
|Requested QoS  |   0x01        |
---------------------------------
|Topic Name     |     “c/d”     |
---------------------------------
|Requested QoS  |   0x02        |
---------------------------------

字节显示:

 -------- ---------------------------------------------------------------------------------------------------------
|                | Description     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|Topic Filter                                                                                                      |
 -----------------------------------------------------------------------------------------------------------------
|byte 1          | Length MSB (0)  |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|byte 2          | Length LSB (3)  |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    1    |
 -----------------------------------------------------------------------------------------------------------------
|byte 3          | 'a'(0x61)       |    0    |    1    |    1    |    0    |    0    |    0    |    0    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 4          | '/'(0x2f)       |    0    |    0    |    1    |    0    |    1    |    1    |    1    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 5          | 'b'(0x62)       |    0    |    1    |    1    |    0    |    0    |    0    |    1    |    0    |
 -----------------------------------------------------------------------------------------------------------------
|Requested QoS                                                                                                     |
 -----------------------------------------------------------------------------------------------------------------
|byte 6          | Requested QoS(1)|    0    |    0    |    0    |    0    |    0    |    0    |    0    |    1    |
 -----------------------------------------------------------------------------------------------------------------
|Topic Filter                                                                                                      |
 -----------------------------------------------------------------------------------------------------------------
|byte 7          | Length MSB (0)  |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|byte 8          | Length LSB (3)  |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    1    |
 -----------------------------------------------------------------------------------------------------------------
|byte 9          | 'c'(0x63)       |    0    |    1    |    1    |    0    |    0    |    0    |    1    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 10         | '/'(0x2f)       |    0    |    0    |    1    |    0    |    1    |    1    |    1    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 11         | 'd'(0x64)       |    0    |    1    |    1    |    0    |    0    |    1    |    0    |    0    |
 -----------------------------------------------------------------------------------------------------------------
|Requested QoS                                                                                                     |
 -----------------------------------------------------------------------------------------------------------------
|byte 12         | Requested QoS(2)|    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ----------------------------------------------------------------------------------------------------------------- 

3.8.4 Response

当Server收到SUBSCRIBE的时候,Server 必须回复SUBACKSUBACK中的Packet Identifier必须和SUBSCRIBE的相同。
如果Client的SUBSCRIBE匹配到了之前有人publish的消息,Server允许先发送PUBLISH后发送SUBACK
如果Server收到的SUBSCRIBE中包含的的Topic已经存在,Server必须使用当前的Topic的Qos取代老的Topic的Qos。新的SUBSCRIBE和老的SUBSCRIBE可能有同样的Topic,但是Qos可能是不同的。任何匹配该Topic的RETAIN的消息必须被再次发送,但是对SUBSCRIBE处理流程没有影响。

如果发送的Topic是新的,则所有RETAIN的且匹配该Topic的消息必须被发送。
如果Server收到的SUBSCRIBE包含多个Topic,Server应该当做收到多个SUBSCRIBE帧进行处理,但是这种情况下也只回复一个SUBACK
Server回复的SUBACK必须对每个Topic有一个状态码,这个状态码需要同时表示对应Topic的Qos或者表示是否失败。Server可能回复的Qos小于SUBSCRIBE 指定的Qos。发给客户端的PUBLISH的Qos必须是回复给Client的SUBACK中的Qos和PUBLISH消息的Qos中的最小值。
Server允许发送重复的
PUBLISH,比如原始对的PUBLISH消息的Qos是1,但是SUBACK`回复的Qos是0。

例子:
如果Client订阅的消息Qos协商是1,但是收到的PUBLISH消息的Qos是0,则回复给对应Client的PUBLISH的Qos是0。这就意味着最多一个数据被Client接收。另一方面,如果收到的PUBLISH消息的Qos是1,则相同的订阅者,收到的Qos是1,这意味着Client可能会收到重复的消息。

如果Client和Server协商的Qos是0,一个Qos为2的PUBLISH消息发给Client的时候,Qos为0,这意味着,在Server发给Client中间可能会丢,但是Server给Client不能发送重复的数据。Qos为1的数据,可能会丢,也可能重复发送。

3.9 SUBACK – Subscribe acknowledgement

SUBACK被Server用来回复Client的SUBSCRIBE
SUBACK包含了状态码列表,这些状态码指定了每个Topic被授予的Qos。

3.9.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (9)     |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    0    |    0    |    1    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                           |
 ---------------------------------------------------------------------------------------------

Remaining Length field
可变头长度(2字节)加上负载长度。

3.9.2 Variable header

可变头包含了SUBSCRIBE中一样的Packet Identifier

3.9.3 Payload

负载包含了状态码的列表,每个状态码对应每个Topic。SUBACK中状态码的顺序必须和SUBSCRIBE中的顺序一致。

被允许的状态码:
0x00 - Success - Maximum QoS 0
0x01 - Success - Maximum QoS 1
0x02 - Success - Maximum QoS 2
0x80 - Failure
其余的状态码被保留没用。

3.10 UNSUBSCRIBE – Unsubscribe from topics

UNSUBSCRIBE是Client用来发送给Server表示自己取消订阅的消息。

3.10.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (10)    |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    0    |    1    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                              |
 ---------------------------------------------------------------------------------------------

Bits 3,2,1 and 0必须设置为0 0 1 0,对于其他形式的,Server必须认为是格式错误,并且关闭连接。

Remaining Length field
可变头长度(2字节)加上负载长度。

3.10.2 Variable header

包含了Packet Identifier

3.10.3 Payload

负载包含了Client想要取消订阅的Topic的列表。Topic必须是UTF-8格式的数据,每个Topic连续的排列着。
负载中必须至少包含一个Topic,没有Topic的UNSUBSCRIBE被认为是protocol violation

3.10.3.1 Payload non normative example
---------------------------------
|Topic Name     |     “a/b”     |
---------------------------------
|Topic Name     |     “c/d”     |
---------------------------------
 -------- ---------------------------------------------------------------------------------------------------------
|                | Description     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|Topic Filter                                                                                                      |
 -----------------------------------------------------------------------------------------------------------------
|byte 1          | Length MSB (0)  |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|byte 2          | Length LSB (3)  |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    1    |
 -----------------------------------------------------------------------------------------------------------------
|byte 3          | 'a'(0x61)       |    0    |    1    |    1    |    0    |    0    |    0    |    0    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 4          | '/'(0x2f)       |    0    |    0    |    1    |    0    |    1    |    1    |    1    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 5          | 'b'(0x62)       |    0    |    1    |    1    |    0    |    0    |    0    |    1    |    0    |
 -----------------------------------------------------------------------------------------------------------------
|Topic Filter                                                                                                      |
 -----------------------------------------------------------------------------------------------------------------
|byte 6          | Length MSB (0)  |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 -------- ---------------------------------------------------------------------------------------------------------
|byte 7          | Length LSB (3)  |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    1    |
 -----------------------------------------------------------------------------------------------------------------
|byte 8          | 'c'(0x63)       |    0    |    1    |    1    |    0    |    0    |    0    |    1    |    1    |
  -----------------------------------------------------------------------------------------------------------------
|byte 9         | '/'(0x2f)       |    0    |    0    |    1    |    0    |    1    |    1    |    1    |    1     |
  -----------------------------------------------------------------------------------------------------------------
|byte 10         | 'd'(0x64)       |    0    |    1    |    1    |    0    |    0    |    1    |    0    |    0    |
 -----------------------------------------------------------------------------------------------------------------

3.10.4 Response

Server必须拿当前订阅的Topic和UNSUBSCRIBE中的Topic一个字节一个字节比较,如果Topic一样,则删除Server保存的Client的订阅Topic,如果没匹配到,则不做上面处理。
如果Server删除Topic:
Server不能再往Client发送对应Topic的消息
Server必须发送完当前正在发送的Qos1和Qos2的消息
Server可以发送缓存的还未发送给Client的消息

Server必须对UNSUBSCRIBE回复UNSUBACK, UNSUBACKPacket Identifier必须和UNSUBSCRIBE的一样。及时Server没有删除任何Topic也要回复UNSUBACK。如果Server收到的UNSUBSCRIBE包含多个Topic,Server必须当做收到多个UNSUBSCRIBE消息来处理,不过只回复一个UNSUBACK

3.11 UNSUBACK – Unsubscribe acknowledgement

对Client UNSUBSCRIBE的响应。

3.11.1 Fixed header

3.10.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (11)    |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    0    |    1    |    1    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                              |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    1    |    0    |
 ---------------------------------------------------------------------------------------------

Remaining Length field
可变头的长度,对于UNSUBACK帧是2字节。

3.11.2 Variable header

可变头包含了UNSUBSCRIBE中一样的Packet Identifier

3.11.3 Payload

3.12 PINGREQ – PING request

PINGREQ是由Client发到Server的帧,它被用来:
1:告诉Server Client是活的,且没有控制帧发送。
2:希望获取Server的响应来判断Server是否是活的。
3:测试网络,判断网络是否是活的。

3.12.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (12)    |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    1    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                              |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------

3.12.2 Variable header

PINGREQ帧没有可变头

3.12.3 Payload

3.12.4 Response

Server必须回复PINGRESP

3.13 PINGRESP – PING response

PINGRESP帧是对PINGREQ的回复。它表示Server是活的。

3.13.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (13)    |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    1    |    0    |    1    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                              |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------

3.13.2 Variable header

3.13.3 Payload

3.14 DISCONNECT – Disconnect notification

DISCONNECT帧是Client发往Server的最后一个帧,它表明Client干净的断开了。

3.14.1 Fixed header

 ---------------------------------------------------------------------------------------------
|    bit     |    7    |    6    |    5    |    4    |    3    |    2    |    1    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 1  |      MQTT Control Packet type (14)    |                Reserved               |
 ---------------------------------------------------------------------------------------------
|            |    1    |    1    |    1    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------
|    byte 2  |                                 Remaining Length                              |
 ---------------------------------------------------------------------------------------------
|            |    0    |    0    |    0    |    0    |    0    |    0    |    0    |    0    |
 ---------------------------------------------------------------------------------------------

Server必须判断Reserved是否全是0。

3.14.2 Variable header

3.14.3 Payload

3.14.4 Response

Client在发送完DISCONNECT之后:
必须关闭传输层连接
不能再次发送任何控制帧

Server一旦收到 DISCONNECT之后:
必须丢弃当前会话的任何的WILL消息,并且不进行PUBLISH。
如果Client不主动关闭连接,Server必须主动关闭连接。

4 Operational behavior

不翻译

猜你喜欢

转载自blog.csdn.net/mrpre/article/details/82531835