CONNECT

3.0 CONTENT – 目录

3.1 CONNECT - 客户端请求连接到服务器 Client requests a connection to a Server

==在客户端建立到服务端的网络连接后,客户端发送给服务端的第一个数据报文必须CONNECT报文== [MQTT-3.1.0-1]

通过单个网络连接,客户端只能发送一次CONNECT报文。==服务端必须将客户端发送第二个CONNECT报文的行为作为协议违规处理并断开客户端的连接== [**MQTT-3.1.0-2]。有关错误处理的信息,请参阅第4.8节。

有效负载包含一个或多个编码字段。这些字段定义了:唯一的客户端标识符、Will主题、Will消息、用户名和密码。除了客户端标识符外的字段都是可选的,而可变报头中的标志位决定了它们的是否存在。

3.1.1 固定报头Fixed header

图例3.1–CONNECT报文的固定报头

位 Bit76543210byte 1MQTT报文类型(1) MQTT Control Packet type保留位Reserved00010000byte 2...剩余长度 Remaining Length

剩余长度字段

剩余长度等于可变报头的长度(10字节)加上有效负载的长度。编码方式参见2.2.3节的说明。

3.1.2 可变报头 Variable header

CONNECT报文的可变报头由四个字段按以下顺序组成:协议名Protocol Name、协议级别Protocol Level、连接标志Connect Flags和保持连接Keep Alive

3.1.2.1 协议名 Protocol Name

图3.2-协议名的字节构成

协议名Protocol Name

描述

7

6

5

4

3

2

1

0

byte 1

长度的最高有效字节MSB(0)

0

0

0

0

0

0

0

0

byte 2

长度的最低有效字节LSB(4)

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

此表中的协议名是用来表示大写的协议名“MQTT”的UTF-8编码的字符串。此字符串的偏移量offset和长度不会因未来版本的MQTT规范而改变。

==如果协议名不正确,服务端可以断开客户端的连接,也可以按照其它规范来继续处理CONNECT报文。对于后一种情况,服务端不得继续按照本规范来处理CONNECT报文== [MQTT-3.1.2-1]

非规范性注解 例如防火墙等的数据包检查工具可以使用协议名来识别MQTT流量。

3.1.2.2 协议级别 Protocol Level

图3.3-协议级别的字节构成

协议级别 Protocol Level

描述

7

6

5

4

3

2

1

0

byte 7

等级(4)

0

0

0

0

0

1

0

0

客户端用8位的无符号值表示协议的修订级别。3.1.1版本协议的协议级别字段的值是4(0x04)。==如果有服务端不支持的协议级别,服务端必须使用CONNACK的0x01(不支持的协议级别)返回码来响应CONNECT报文然后断开客户端连接,== [MQTT-3.1.2-2]

3.1.2.3 连接标志 Connect Flags

连接标志字节包含许多用于指定MQTT连接行为的参数。它还指出有效负载中字段的存在与否。

图3.4-连接标志位

位 Bit76543210用户名标志位 User Name Flag密码标志 Password Flag遗嘱消息保留位 Will Retain遗嘱消息服务质量等级 Will QoS遗嘱标志位 Will Flag清理会话志位 Clean Session保留标志位 Reservedbyte 8XXXXXXX0

==服务端必须验证CONNECT控制报文的保留标志位(第0位)是否被设置0,如果不是0,则必须断开客户端连接== [MQTT-3.1.2-3]

3.1.2.4 清理会话 Clean Session

位置:连接标志字节的第1位

该位指定了会话状态的处理方式。

客户端和服务端可以保存会话状态,以支持多网络连接的可靠消息传输。此标志位用于控制会话状态的生存时间。

==如果CleanSession标志被设置为0,则服务端必须基于当前会话的状态(使用客户端标识符来标识)来恢复与客户端的通信。如果没有与客户端标识符关联的会话,服务端必须创建一个新的会话。在客户端与服务端断开连接后,客户端和服务端必须保存会话。== [MQTT-3.1.2-4]。==当CleanSession志为0的会话连接断开之后,对于客户端在断开连接时就有的匹配任何订阅的QoS 1和QoS 2级别的消息,服务端必须进一步将它们保存为会话状态的一部分。== [MQTT-3.1.2-5]。服务端也可以保存满足相同条件的QoS 0级别的消息。

==如果CleanSession标志被设置为1,客户端和服务端必须放弃所有之前的会话并建立一个新的会话。此会话的持续时间和网络连接的时长一样。与这个会话关联的状态数据不能在任何之后的会话中重用== [MQTT-3.1.2-6]

客户端中的会话状态包括:

  • 已经发送到服务端但尚未完成确认的QoS 1和QoS 2级别的消息

  • 已从服务端接收但尚未完成确认的QoS 2级别的消息。

服务端中的会话状态包括:

  • 会话存在,即使会话状态的其它部分都是空。

  • 客户端的订阅消息

  • 已发送到客户端但尚未完成确认的QoS 1和QoS 2级别的消息。

  • 等待传输给客户端的QoS 1和QoS 2级别的消息。

  • 已从客户端接收的但尚未完成确认的QoS 2级别的消息。

  • 可选项,等待发送给客户端的QoS 0级别的消息。

==保留消息不是服务端会话状态的一部分,会话终止时不得删除保留消息== [MQTT-3.1.2.7]

有关存储状态的详细信息和限制,请参阅第4.1节。

CleanSession标志被设置为1时,客户端和服务端无需以原子操作来处理状态删除。

非规范性注解 为了确保在发生故障时的状态一致性,客户端应该将CleanSession标志设置为1并尝试重复连接,直到连接成功。 非规范性注解 通常,客户端将始终使用设置为0或1的CleanSession标志来进行连接,并不会在两个值之间进行切换,该选择取决于具体的应用。CleanSession标志设置为1的客户端将不会收到旧的应用消息,并且每次连接都需要重新订阅相关主题。CleanSession标志设置为0的客户端会收到所有在它断开连接时发布的QoS 1和QoS 2级别的消息。因此,为确保断开连接时不丢失消息,请将CleanSession标志设置为0并使用QoS 1或 QoS 2级别。 非规范性注解 当客户端以CleanSession标志0连接时,这就表示它请求服务端在断开连接后保留它的MQTT会话状态。如果客户端打算在之后重连到这个服务端,它应该只使用CleanSession标志0来进行连接。如果客户端确定之后不会再使用这个会话,应该将CleanSession标志设置为1并最后连接一次,然后断开连接。

3.1.2.5 遗嘱标志 Will Flag

位置:连接标志的第2位。

==遗嘱标志设置为1,则表示如果接受连接请求,遗嘱消息必须存储在服务端上并且关联此网络连接。当网络连接随后关闭时,服务端必须发布这个遗嘱消息,除非服务端在收到DISCONNECT报文时已经删除了这个遗嘱消息== [MQTT-3.1.2-8]

遗嘱消息发布的条件,包括但不限于:

  • 服务端检测到了I/O错误或网络故障时。

  • 客户端在保持连接Keep Alive的时间内无法通讯时。

  • 客户端未先发送DISCONNECT报文直关闭了网络连接时。

  • 由于协议错误,服务端关闭网络连接时。

==如果遗嘱标志设置为1,服务端将会使用连接标志中的Will QoSWill Retain字段,同时有效负载中必须包含遗嘱主题和Will Message字段== [MQTT-3.1.2-9]

==遗嘱消息一旦被发布或者服务端从客户端收到了发送的DISCONNECT报文,遗嘱消息就必须从存储的会话状态中移除== [MQTT-3.1.2-10]

==如果遗嘱标志设置为0,连接标志中的Will QoSWill Retain字段必须设置为0,并且有效负载中不能出现遗嘱主题和Will Message字段== [MQTT-3.1.2-11]

==如果遗嘱标志设置为0,网络连接断开时,就不能发布遗嘱消息== [MQTT-3.1.2-12]

服务端应该及时地发布遗嘱消息。在服务端关机或故障的情况下,服务端可以在重启之后再发布遗嘱消息。如果出现了这种情况,在服务端发生故障与发布遗嘱消息之间可能会有延迟时间。

3.1.2.6 遗嘱消息服务质量等级 Will QoS

位置:连接标志的第4和第3位。

这两位用于指定发布遗嘱消息时要使用的Qos

==如果遗嘱标志设置为0,Will QoS必须设置为0(0x00)==[MQTT-3.1.2-13]

==如果遗嘱标志设置为1,Will QoS的值可以是0(0x00)、1(0x01)、2(0x02),但它的值不能等于3(0x03)== [MQTT-3.1.2-14]

3.1.2.7 遗嘱消息保留位 Will Retain

位置:连接标志的第5位。

该位指定了遗嘱消息是否以保留形式发布。

==如果遗嘱标志设置为0,Will Retain标志也必须设置为0== [MQTT-3.1.2-15]

==如果遗嘱标志设置为1==:

  • ==如果Will Retain被设置为0,服务端必须将遗嘱消息当作非保留消息发布== [MQTT-3.1.2-16]

  • ==如果Will Retain被设置为1,服务端必须将遗嘱消息当作保留消息发布== [MQTT-3.1.2-17]

3.1.2.8 用户名标志 User Name Flag

位置:连接标志的第7位。

==如果用户名标志被设置为0,有效负载中不得包含用户名字段== [MQTT-3.1.2-18]

==如果用户名标志被设置为1,有效负载中必须包含用户名字段== [MQTT-3.1.2-19]

3.1.2.9 密码标志 Password Flag

位置:连接标志的第6位。

==如果密码标志被设置为0,有效负载中不得包含密码字段== [MQTT-3.1.2-20]

==如果密码标志被设置为1,有效负载中必须包含密码字段== [MQTT-3.1.2-21]

==如果用户名标志被设置为0,密码标志必须设置为0== [MQTT-3.1.2-22]

3.1.2.10 保持连接 Keep Alive

图3.5 保持连接字节构成

位 Bit76543210byte 9保持连接位的最高有效字节 Keep Alive MSBbyte 9保持连接位的最低有效字节 Keep Alive LSB

Keep Alive是一个以秒为单位的时间间隔,以一个16位字形式表示,代表从客户端传输完成一个控制报文的时间点到发送下一个报文的时间点之间的允许的最大时间间隔。==客户端负责保证控制报文发送的时间间隔不超过Keep Alive值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ报文== [MQTT-3.1.2-23]

无论Keep Alive的值是多少,客户端在任何时候都可以发送PINGREQ报文,并使用PINGRESP报文判断来网络和服务端的活动状态。

==如果Keep Alive值非0,并且服务端在1.5倍的Keep Alive时间内没有收到来自客户端的控制报文,它就必须断开客户端的网络连接,就好像发生了网络故障一样==。 [MQTT-3.1.2-24]

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

Keep Alive值为0表示关闭Keep Alive功能。这意味着,服务端不需要因为客户端不活跃就断开连接。注意:不管客户端提供的Keep Alive值是多少,服务器可以随时断开它认为处于非活动状态或无响应状态的客户端。

非规范性注解 Keep Alive实际值是由应用指定的,通常是几分钟,允许的最大值是18小时12分15秒。

3.1.2.11 可变报头非规范示例

图3.6 -可变报头非规范示例

描述

7

6

5

4

3

2

1

0

协议名Protocol Name

byte 1

长度的最高有效字节MSB(0)

0

0

0

0

0

0

0

0

byte 2

长度的最低有效字节LSB(4)

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

协议级别 Protocol Level

byte 7

等级(4)

0

0

0

0

0

1

0

0

连接标志 Connect Flags

byte 8

User Name Flag (1) Password Flag (1) Will Retain (0) Will QoS (01) Will Flag (1) Clean Session (1) Reserved (0)

1

1

0

0

1

1

1

0

保持连接Keep Alive

byte 9

保持连接的最高有效字节MSB(0)

0

0

0

0

0

0

0

0

byte 10

保持连接的最低有效字节LSB(10)

0

0

0

0

1

0

1

0

3.1.3 有效负载 Payload

CONNECT报文的有效负载包含一个或多个以长度为前缀的字段,其存在由可变报头中的标志确定。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码 [MQTT-3.1.3-1]

3.1.3.1 客户端标识符 Client Identifier

服务端使用客户端标识符来识别客户端。==连接到服务端的每个客户端都有唯一的客户端标识符。客户端和服务端都必须使用客户端标识符来识别两者之间的MQTT会话相关的状态== [MQTT-3.1.3-2]

==客户端标识符 必须存在而且必须CONNECT报文有效负载的第一个字段== [MQTT-3.1.3-3]

==客户端标识符必须是第1.5.3节中定义的UTF-8编码字符串== [MQTT-3.1.3-4]

==服务端必须允许1到23个字节长的UTF-8编码的客户端标识符进行访问,并且客户端标识符只能包含这些字符:“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”(数字和大小写字母)==[MQTT-3.1.3-5]

服务端可以允许编码后超过23个字节的客户端标识符进行访问。服务端可以允许包含上面列表中未列出的客户端标识符进行访问。

==服务端可以允许客户端提供一个长度为0字节的客户端标识符,但如果这样做了,服务端必须将这看作特殊情况并为其分配唯一的客户端标识符。它必须处理CONNECT数据包,就好像客户端提供了唯一的客户端标识符== [MQTT-3.1.3-6]

==如果客户端提供了0字节的客户端标识符,客户端必须同时将CleanSession标志置1== [MQTT-3.1.3-7]

==如果客户端提供且CleanSession标志为0的0字节客户端标识符,服务端必须发送返回码为0x02(表示标识符被拒绝)的CONNACK报文响应客户端的CONNECT报文,然后关闭网络连接== [MQTT-3.1.3-8]

==如果服务端拒绝了这个客户端标识符,它必须发送返回码为0x02(表示标识符被拒绝)的CONNACK报文响应客户端的CONNECT报文,然后关闭网络连接== [MQTT-3.1.3-9]

非规范性注解

客户端实现可以提供一个方便的方法用于生成随机的客户端标识符。当CleanSession标志设置为0时,应该主动放弃使用这种方法。

3.1.3.2 遗嘱主题 Will Topic

如果遗嘱标志设置为1,有效负载中的下一个字段就是遗嘱主题。==Will Topic必须是第1.5.3节定义的UTF-8编码字符串== [MQTT-3.1.3-10]

3.1.3.3 遗嘱消息 Will Message

如果遗嘱标志设置为1,有效负载中的下一个字段是遗嘱消息。遗嘱消息定义了将发布到遗嘱主题的应用消息,如第3.1.2.5节所述。应用消息由双字节长度组成,随后是表示为0个或多个字节的序列的遗嘱消息的有效负载。双字节的长度中给出了随后数据的字节数,这不包含长度字段本身占用的双字节。

当遗嘱消息发布到遗嘱主题时,遗嘱消息的有效负载只包含应用消息字段的数据部分,不包含开头的两个长度字节。

3.1.3.4 用户名 User Name

如果用户名标志设置为1,有效负载的下一个字段就是它。==用户名必须是第1.5.3节定义的UTF-8编码字符串== [MQTT-3.1.3-11]。服务端可以将它用于身份验证和授权。

3.1.3.5 密码 Password

如果密码标志设置为1,有效负载的下一个字段就是它。密码字段包含0到65535字节的二进制数据,前缀为一个双字节长度字段,用于指示二进制数据使用的字节数(它不包括长度字段本身占用的双字节)。

图3.7-密码字节的组成

位 Bit76543210byte 1数据长度的最高有效字节 Data length MSBbyte 2数据长度的最低有效字节 Data length LSBbyte 3...数据,如果数据长度>0 Data, if length > 0.

3.1.4 响应 Response

请注意:服务器可以在同一个TCP端口或其他网络端点上支持多种协议(包括本协议的早期版本)。如果服务器确定协议是MQTT 3.1.1,那么它按照下面的方法验证连接请求。

  1. 如果服务器在网络连接建立后的合理时间内没有收到CONNECT报文,服务端应该关闭这个连接。

  2. ==服务端必须确认CONNECT报文符合第3.1 节的规定,如果不符合规范,服务端将关闭网络连接并不发送CONNACK报文== [MQTT-3.1.4-1]

  3. 服务端可以检查CONNECT报文的内容是否符合进一步的限制,并可以执行身份验证和授权检查。如果任何一项检查没通过,它应该按照第3.2节所说的发送一个适当的、返回码非0的CONNACK响应,并必须关闭这个网络连接。

如果验证成功,服务端会执行下列步骤:

  1. ==如果客户端标识符表明客户端已经连接到这个服务端,那么服务端必须断开现有的客户端连接== [MQTT-3.1.4-2]

  2. ==服务端必须按照 3.1.2.4节所说的执行CleanSession的处理== [MQTT-3.1.4-3]

  3. ==服务端必须发送返回码为0的CONNACK报文来确认CONNECT报文 [MQTT-3.1.4-4]

  4. 开始消息分发和对保持连接状态的监视。

允许客户端在发送CONNECT报文之后立即发送更多的控制报文;客户端不需要等待服务端的CONNACK报文。==如果服务端拒绝了CONNECT,它就不能处理客户端在CONNECT报文之后发送的任何数据== [MQTT-3.1.4-5]

非规范性注解 客户端通常会等待CONNACK报文。但是,如果客户端在收到CONNACK之前就自由地发送控制报文,由于不需要去监管连接状态,这就可以简化客户端的实现。如果服务器拒绝连接,客户端接受,它在从接收到来自服务器的CONNACK报文之前发送的数据都将得不到处理。

Last updated