客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文

在一个网络连接上,客户端只能发送一次CONNECT报文。

固定报头 Fixed header

MQTT协议(二)>>> 【CONNECT】连接服务器
剩余长度等于可变报头的长度(10字节)加上有效载荷的长度。

可变报头 Variable header

CONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。

协议名 Protocol Name

协议名是表示协议名 MQTT 的UTF-8编码的字符串。
MQTT协议(二)>>> 【CONNECT】连接服务器

协议级别 Protocol Level

MQTT协议(二)>>> 【CONNECT】连接服务器
客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)

如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK 报文响应CONNECT 报文,然后断开客户端的连接。

连接标志 Connect Flags

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

MQTT协议(二)>>> 【CONNECT】连接服务器
服务端必须验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接。

1. 清理会话 Clean Session

如果清理会话(CleanSession)标志被设置为0,服务端必须基于当前会话(使用客户端标识符识别)的状态恢复与客户端的通信

如果清理会话(CleanSession)标志被设置为1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间,即网络连接断开,会话结束。与这个会话关联的状态数据不能被任何之后的会话重用
MQTT协议(二)>>> 【CONNECT】连接服务器
为了确保在发生故障时状态的一致性,客户端应该使用会话状态标志1重复请求连接,直到连接成功。

清理会话标志0的客户端连接时,它请求服务端在连接断开后保留它的MQTT会话状态。如果打算在之后的某个时间点重连到这个服务端,客户端连接应该只使用清理会话标志0。
当客户端决定之后不再使用这个会话时,应该将清理会话标志设置为1最后再连接一次,然后断开连接。

2. 遗嘱标志 Will Flag

当一个客户端与服务端断开连接,服务端将遗嘱消息分发给订阅了该遗嘱主题的其他客户端

网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到DISCONNECT报文时删除了这个遗嘱消息
MQTT协议(二)>>> 【CONNECT】连接服务器
如果遗嘱标志被设置为1,连接标志中的Will QoS和Will Retain字段会被服务端用到,同时有效载荷中必须包含Will Topic和Will Message字段
如果遗嘱标志被设置为0,连接标志中的Will QoS和Will Retain字段必须设置为0,并且有效载荷中不能包含Will Topic和Will Message字段

3&4. 遗嘱QoS Will QoS

这两位用于指定发布遗嘱消息时使用的服务质量等级。

如果遗嘱标志被设置为0,遗嘱QoS也必须设置为0
如果遗嘱标志被设置为1,遗嘱QoS的值可以等于0(0x00)1(0x01)2(0x02)

5. 遗嘱保留 Will Retain

如果遗嘱消息被发布时需要保留,需要指定这一位的值。

如果遗嘱标志被设置为0,遗嘱保留(Will Retain)标志也必须设置为0。
如果遗嘱标志被设置为1:

  • 如果遗嘱保留被设置为0,服务端必须将遗嘱消息当作非保留消息发布;
  • 如果遗嘱保留被设置为1,服务端必须将遗嘱消息当作保留消息发布。

6. 密码标志 Password Flag

如果密码(Password)标志被设置为0,有效载荷中不能包含密码字段
如果密码(Password)标志被设置为1,有效载荷中必须包含密码字段

如果用户名标志被设置为0密码标志也必须设置为0

7. 用户名标志 User Name Flag

百度云、阿里云支持“MQTT 用户名+密码”的方式接入物联网平台。

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

保持连接 Keep Alive

MQTT协议(二)>>> 【CONNECT】连接服务器
保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔

客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ 报文

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

保持连接的值为零表示关闭保持连接功能


以上就是关于可变报头各个组成部分的详细讲解,接下来看个栗子 ????
MQTT协议(二)>>> 【CONNECT】连接服务器

有效载荷 Payload

CONNECT 报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段

如果包含的话,必须按这个顺序出现客户端标识符遗嘱主题遗嘱消息用户名密码

客户端标识符 Client Identifier

客户端标识符 (ClientId) 必须存在而且必须是CONNECT 报文有效载荷的第一个字段

服务端使用客户端标识符 (ClientId) 识别客户端。

遗嘱主题 Will Topic

如果遗嘱标志被设置为1,有效载荷的下一个字段是遗嘱主题

遗嘱消息 Will Message

如果遗嘱标志被设置为1,有效载荷的下一个字段是遗嘱消息

这个字段由一个两字节的长度遗嘱消息的有效载荷组成,表示为零字节或多个字节序列。长度给出了跟在后面的数据的字节数,不包含长度字段本身占用的两个字节。

用户名 User Name

如果用户名(User Name)标志被设置为1,有效载荷的下一个字段就是它。

服务端可以将它用于身份验证和授权。

密码 Password

如果密码(Password)标志被设置为1,有效载荷的下一个字段就是它。

密码字节:
MQTT协议(二)>>> 【CONNECT】连接服务器

响应 Response

服务器可以在同一个TCP端口或其他网络端点上支持多种协议

如果服务器确定协议是MQTT 3.1.1,那么它按照下面的方法验证连接请求

  1. 网络连接建立后,如果服务端在合理的时间内没有收到CONNECT 报文,服务端应该关闭这个连接;
  2. 服务端必须按照要求验证CONNECT 报文,如果报文不符合规范,服务端不发送CONNACK 报文直接关闭网络连接;
  3. 服务端可以检查CONNECT 报文的内容是不是满足任何进一步的限制,可以执行身份验证和授权检查。如果任何一项检查没通过,它应该发送一个适当的、返回码非零的CONNACK 响应,并且必须关闭这个网络连接。


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

  1. 如果ClientId 表明客户端已经连接到这个服务端,那么服务端必须断开原有的客户端连接;
  2. 服务端必须按照之前的描述执行清理会话的过程;
  3. 服务端必须发送返回码为零的CONNACK 报文作为CONNECT 报文的确认响应;
  4. 开始消息分发和保持连接状态监视。

允许客户端在发送CONNECT 报文之后立即发送其它的控制报文;客户端不需要等待服务端的CONNACK 报文。
如果服务端拒绝了CONNECT,它不能处理客户端在CONNECT 报文之后发送的任何数据。

相关文章: