3.1 CONNECT - 客户端请求与服务器的连接
在客户端向服务器建立网络连接之后,从客户端发送到服务器的第一个数据包必须是CONNECT数据包 [MQTT-3.1.0-1]。
客户端只能通过网络连接发送一次CONNECT数据包。服务器必须处理从客户端发送的第二个CONNECT数据包作为协议违规并断开客户端 [MQTT-3.1.0-2]。有关处理错误的信息,请参见第4.8节。
有效载荷包含一个或多个编码字段。它们为客户端指定唯一的客户端标识符,Will主题,Will Message,用户名和密码。除客户端标识符之外的所有标识符都是可选的,它们的存在是根据变量头中的标志确定的。
3.1.1 Fixed header 固定标题
位 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
字节1 |
MQTT控制包类型(1) |
保留的 |
||||||
|
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
字节2 ... |
剩余长度 |
剩余长度字段
剩余长度是变量头的长度(10个字节)加上有效负载的长度。它以2.2.3节中描述的方式编码。
3.1.2 Variable header 变量头
CONNECT数据包的变量头按以下顺序包含四个字段:协议名称,协议级别,连接标志和保持活动。
|
描述 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
协议名称 |
|||||||||
字节1 |
长度MSB(0) |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
字节2 |
长度LSB(4) |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
字节3 |
'M' |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
字节4 |
'Q' |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
1 |
字节5 |
'T' |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
字节6 |
'T' |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
协议名称是UTF-8编码的字符串,表示协议名称“MQTT”,大写如图所示。MQTT规范的未来版本不会更改字符串,其偏移量和长度。
如果协议名称不正确,则服务器可以断开客户端,或者可以根据其他规范继续处理CONNECT数据包。在后一种情况下,服务器不得继续按照此规范 [MQTT-3.1.2-1] 继续处理CONNECT数据包。
非规范性评论
数据包检查员(如防火墙)可以使用协议名称来识别MQTT流量。
|
描述 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
协议级别 |
|||||||||
字节7 |
等级(4) |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
8位无符号值,表示客户端使用的协议的修订级别。协议版本3.1.1的协议级别字段的值为4(0x04)。服务器必须使用CONNACK返回码0x01(不可接受的协议级别)响应CONNECT数据包,如果服务器 [MQTT-3.1.2-2] 不支持协议级别,则断开客户端连接。
Connect Flags字节包含许多指定MQTT连接行为的参数。它还指示有效载荷中是否存在字段。
位 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
用户名标志 |
密码标志 |
是否保留标识 |
QOS级别 |
will flag |
清楚session标识 |
保留位 |
|
字节8 |
X |
X |
X |
X |
X |
X |
X |
0 |
服务器必须验证在CONNECT控制分组中的保留标志被设为零并断开客户端,如果它不是零 [MQTT-3.1.2-3] 。
位置: Connect Flags字节的第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,直到连接成功为止。
非规范性评论
通常,客户端将始终使用CleanSession设置为0或CleanSession设置为1进行连接,而不是在两个值之间进行交换。选择取决于应用程序。将CleanSession设置为1的客户端将不会收到旧的应用程序消息,并且每次连接时都必须重新订阅它感兴趣的任何主题。将CleanSession设置为0的客户端将接收断开连接时发布的所有QoS 1或QoS 2消息。因此,要确保在断开连接时不丢失消息,请使用QoS 1或QoS 2,并将CleanSession设置为0。
非规范性评论
当客户端连接CleanSession设置为0时,它请求服务器在断开连接后保持其MQTT会话状态。如果客户端打算在稍后的某个时间点重新连接到服务器,则客户端应仅与CleanSession设置为0连接。当客户端确定它没有进一步用于会话时,它应该与CleanSession设置为1进行最终连接,然后断开连接。
位置: Connect Flags的第2位。
WILL MESSAGE : 遗嘱消息
如果Will Flag设置为1,则表示如果接受Connect请求,则Will Message必须存储在服务器上并与网络连接相关联。除非在收到DISCONNECT数据包[MQTT-3.1.2-8] 后服务器删除了Will Message,否则必须在网络连接随后关闭时发布Will Message消息。
发布遗嘱消息的情况包括但不限于:
- 服务器检测到I / O错误或网络故障。
- 客户端无法在Keep Alive时间内进行通信。
- 客户端在未先发送DISCONNECT数据包的情况下关闭网络连接。
- 由于协议错误,服务器关闭网络连接。
如果Will Flag设置为1,则服务器将使用Connect Flags中的Will QoS和Will Retain字段,并且有效负载中必须存在Will Topic和Will Message字段 [MQTT-3.1.2-9]。
一旦发布或服务器已从客户端[MQTT-3.1.2-10] 收到DISCONNECT数据包,则必须从服务器中存储的会话状态中删除Will消息。
如果Will Flag设置为0,则Connect Flags中的Will QoS和Will Retain字段必须设置为零,并且Will Top Topic和Will Message字段不得出现在有效载荷[MQTT-3.1.2-11]中。
如果将Will Flag设置为0,则当此网络连接结束时,不得发布Will Message消息[MQTT-3.1.2-12] 。
服务器应该立即发布Will Messages。在服务器关闭或故障的情况下,服务器可以推迟发布Will Messages直到后续重新启动。如果发生这种情况,服务器遇到故障和发布Will Message之间可能会有一段延迟。
QOS:Quality of Service
位置: Connect Flags的第4位和第3位。
这两个位指定发布Will Message时要使用的QoS级别。
如果Will Flag设置为0,则Will QoS必须设置为0 (0x00)[MQTT-3.1.2-13]。
如果Will Flag设置为1,则Will QoS的值可以是0(0x00),1(0x01)或2(0x02)。它不能是3(0x03)[MQTT-3.1.2-14]。
位置: Connect Flags的第5位。
此位指定在发布时是否保留Will Message。
如果Will Flag设置为0,则Will Retain Flag必须设置为0 [MQTT-3.1.2-15]。
如果Will Flag设置为1:
- 如果Will Retain设置为0,则服务器必须将Will Message作为非保留消息 [MQTT-3.1.2-16]发布。
- 如果Will Retain设置为1,则服务器必须将Will Message作为保留消息[MQTT-3.1.2-17]发布。
位置: Connect Flags的第7位。
如果用户名标志设置为0,则有效负载 [MQTT-3.1.2-18]中不得出现用户名。
如果用户名标志设置为1,则有效负载 [MQTT-3.1.2-19]中必须存在用户名。
位置: Connect Flags字节的第6位。
如果密码标志设置为0,则有效负载 [MQTT-3.1.2-20]中不得出现密码。
如果密码标志设置为1,则有效负载 [MQTT-3.1.2-21]中必须存在密码。
如果用户名标志设置为0,则密码标志必须设置为0 [MQTT-3.1.2-22]。
位 |
7 |
6 |
五 |
4 |
3 |
2 |
1 |
0 |
字节9 |
保持活力MSB |
|||||||
字节10 |
保持活着LSB |
Keep Alive是以秒为单位测量的时间间隔。表示为16位字,它是客户端完成发送一个控制数据包的点与它开始发送下一个控制数据包的点之间允许经过的最大时间间隔。客户有责任确保发送的控制数据包之间的间隔不超过保持活动值。在没有发送任何其他控制数据包的情况下,客户端必须发送PINGREQ数据包 [MQTT-3.1.2-23]。
无论Keep Alive值如何,客户端都可以随时发送PINGREQ,并使用PINGRESP确定网络和服务器是否正常工作。
如果Keep Alive值为非零且服务器在Keep Alive时间段的一倍半内没有从客户端收到控制数据包,它必须断开与客户端的网络连接,就好像网络发生故障一样 [MQTT -3.1.2-24] 。
如果客户端在发送PINGREQ后的一段合理时间内没有收到PINGRESP数据包,它应该关闭与服务器的网络连接。
保持活动值为零(0)具有关闭保持活动机制的效果。这意味着,在这种情况下,服务器不需要以不活动为由断开客户端。
请注意,允许服务器随时断开它确定为无效或无响应的客户端,无论该客户端提供的保持活动值如何。
非规范性评论
Keep Alive的实际值是特定于应用程序的; 通常这是几分钟。最大值为18小时12分15秒。
3.1.2.11 变量头非规范性示例
3.1.3 Payload
CONNECT数据包的有效负载包含一个或多个长度前缀字段,其存在由变量头中的标志确定。这些字段(如果存在)必须出现在客户端标识符,主题,消息,用户名,密码[MQTT-3.1.3-1]的顺序中。
3.1.3.1 Client Identifier 客户端 id必须唯一
客户端标识符(ClientId)将客户端标识为服务器。连接到服务器的每个客户端都有一个唯一的ClientId。客户端和服务器必须使用ClientId来识别它们与客户端和服务器之间的MQTT会话相关的状态 [MQTT-3.1.3-2] 。
客户端标识符(ClientId)必须存在,并且必须是CONNECT数据包有效负载 [MQTT-3.1.3-3]中的第一个字段。
ClientId必须是第1.5.3 节[MQTT-3.1.3-4]中定义的UTF-8编码字符串。
服务器必须允许ClientIds,其长度在1到23个UTF-8编码字节之间,并且只包含字符
“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ” [MQTT-3.1.3-5] 。
服务器可以允许包含超过23个编码字节的ClientId。服务器可以允许ClientId包含上面给出的列表中未包含的字符。
服务器可以允许客户端提供长度为零字节的ClientId,但是如果它这样做,则服务器必须将其视为特殊情况并为该客户端分配唯一的ClientId。它必须处理CONNECT数据包,就像客户端提供了唯一的ClientId [MQTT-3.1.3-6]一样。
如果客户端提供零字节ClientId,则客户端还必须将CleanSession设置为1 [MQTT-3.1.3-7]。
如果客户端提供一个零字节的ClientId,其CleanSession设置为0,则服务器必须使用CONNACK返回代码0x02(标识符被拒绝)响应CONNECT数据包,然后关闭网络连接 [MQTT-3.1.3-8] 。
如果服务器拒绝ClientId,它必须使用CONNACK返回代码0x02(标识符被拒绝)响应CONNECT数据包,然后关闭网络连接 [MQTT-3.1.3-9] 。
非规范性评论
客户端实现可以提供生成随机ClientId的便捷方法。当CleanSession设置为0时,应该主动阻止使用这种方法。
如果Will Flag设置为1,则Will Topic是有效负载中的下一个字段。Will Topic必须是第1.5.3 节[MQTT-3.1.3-10]中定义的UTF-8编码字符串。
如果Will Flag设置为1,则Will Message是有效载荷中的下一个字段。Will Message定义了要发布到Will Topic的应用程序消息,如3.1.2.5节所述。该字段由两个字节长度组成,后跟Will Message的有效负载,表示为零个或多个字节的序列。长度给出了后面数据中的字节数,不包括长度本身占用的2个字节。
当Will Message发布到Will Topic时,其有效负载仅包含该字段的数据部分,而不是前两个长度字节。
如果用户名标志设置为1,则这是有效负载中的下一个字段。用户名必须是第1.5.3 节[MQTT-3.1.3-11]中定义的UTF-8编码字符串。 它可以由服务器用于身份验证和授权。
如果密码标志设置为1,则这是有效负载中的下一个字段。密码字段包含0到65535字节的二进制数据,前缀为两字节长度字段,表示二进制数据使用的字节数(它不包括长度字段本身占用的两个字节)。
位 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
字节1 |
数据长度MSB |
|||||||
字节2 |
数据长度LSB |
|||||||
字节3 .... |
数据,如果长度> 0。 |
3.1.4 Response 回应
请注意,服务器可以在同一TCP端口或其他网络端点上支持多个协议(包括此协议的早期版本)。如果服务器确定协议是MQTT 3.1.1,那么它将验证连接尝试,如下所示。
1. 如果服务器在建立网络连接后的合理时间内未收到CONNECT数据包,则服务器应该关闭连接。
2. 如果CONNECT数据包不符合[MQTT-3.1.4-1],它必须验证CONNECT数据包是否符合第3.1 节并关闭网络连接而不发送CONNACK 。
3. 服务器可以检查CONNECT数据包的内容是否满足任何进一步的限制,并且可以执行身份验证和授权检查。如果这些检查中的任何一个失败,它应该发送一个带有非零返回码的适当的CONNACK响应,如3.2节所述,它必须关闭网络连接。
如果验证成功,则服务器执行以下步骤。
1. 如果ClientId表示已连接到服务器的客户端,则服务器必须断开现有客户端[MQTT-3.1.4-2]。
2. 服务器必须执行第3.1.2.4 节[MQTT-3.1.4-3]中描述的CleanSession处理。
3. 服务器必须使用包含零返回码[MQTT-3.1.4-4] 的CONNACK包来确认CONNECT数据包。
4. 启动消息传递并保持活动监控。
允许客户端在发送CONNECT数据包后立即发送更多控制数据包; 客户端无需等待CONNACK数据包从服务器到达。如果服务器拒绝CONNECT,它必须在CONNECT数据包 [MQTT-3.1.4-5] 之后不处理客户端发送的任何数据。
非规范性注释
客户端通常等待CONNACK数据包,但是,如果客户端在收到CONNACK之前利用其自由发送控制数据包,则可能会简化客户端实施,因为它不必警告连接状态。客户端接受,如果服务器拒绝连接,则在从服务器接收CONNACK数据包之前发送的任何数据都将不会被处理。