1、什么是MQTT
1.1、MQTT特点
MQTT工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特征:
1.2、MQTT协议原理-协议实现方式
2、MQTT协议原理-网络传输与应用消息
2.1、MQTT协议原理-客户端
一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:
2.2、MQTT协议原理-服务端
MQTT服务器以称为“消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:•接受来自客户的网络连接
•接受客户发布的应用信息
•处理来自客户端的订阅和退订请求
•向订阅的客户转发应用程序消息
2.3、MQTT协议原理-订阅、主题、会话
订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。
连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。
一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。
消息订阅者所具体接收的内容
3、MQTT协议数据包
3.1、MQTT协议数据包-固定报头
3.1.1、MQTT协议数据包-固定报头-控制报文的类型
固定报头总结:
CONNECT: 0x10 ,第二字节剩余长度待定??数据内容应该会表示连接那个服务端
CONNACK:0x20,0x02
PUBLISH:0x3?(低四位待定),第二字节剩余长度待定,数据内容应该会表示发布那个主题
PUBACK:0x40,0x02
PUBREC:0x50,0x02
PUBREL:0x62,0x02
PUBCOMP:0x70,0x02
SUBSCRIBE:0x80,第二字节剩余长度待定??数据内容应该会表示订阅那个主题
SUBACK:0x90,第二个字节剩余长度待定,数据内容应该会表示订阅成功还是失败
UNSUBSCRIBE:0xA2 ,第二个字节剩余长度待定,数据内容应该会表示取消那个主题
UNSUBACK:0xB0,0x02
PINGREQ: 0xC0,0x00
PINGRESP:0xD0,0x00
DISCONNECT:0xE0,0x00
3.1.2、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位
固定报头第 1 个字节的剩余的 4 位 [3-0]包含每个 MQTT 控制报文类型特定的标志,见 表格 2.2 -标志位。
表格 2.2 中任何标记为“保留”的标志位, 都是保留给以后使用的, 必须设置为表格中列出的值 [MQTT-
2.2.2-1]。 如果收到非法的标志, 接收者必须关闭网络连接
DUP1 | =控制报文的重复分发标志 |
QoS2 | = PUBLISH 报文的服务质量等级 |
RETAIN3 = PUBLISH 报文的保留标志
PUBLISH 控制报文中的 DUP, QoS 和 RETAIN 标志的描述见 3.3.1 节
3.1.2.1、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-DUP
3.1.2.2、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-服务质量等级 QOS
3.1.2.3、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-will遗言
will遗言虽然不属于指定控制报文类型的标志位,但是和Retain是相关的
3.1.2.3、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-Retain
3.1.3、MQTT协议数据包-固定报头-剩余长度
使用变成编码(1到4个字节表示,即最大可表示256M,每个字节可编码128个数值+1个延续位(最高位是延续位表示是否有更多字节,低7位表示128个数值)):
剩余长度表示当前报文剩余部分的字节数,包括可变报头和负载的数据,剩余长度字段使用一个变长度表示方案,对小于128的值它使用单字节表示。更大的值按下面的方式处理:低7位有效位用于表示数据,最高有效位用于指示是否有更多的字节,剩余长度字段最大4个字节。例如,十进制64会被表示为一个字节,数值是64,十六进制表示为0x40,十进制321(65+2*128)被表示为两个字节,第一个字节是65+128=193。注意最高位为1表示后面至少还有一个字节,第二个字节2
详情请查看文档:https://blog.csdn.net/caofengtao1314/article/details/116482822
3.2、MQTT协议数据包-可变报头
报文标识符用来区分报文,特别是在重发的报文中用来标识是否是同一个报文,并在需要应答的场景中用于确定是对哪个发送报文的应答。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
很多控制报文的可变报头部分包含一个两字节的报文标识符字段。 这些报文是 PUBLISH(QoS>0 时) ,
PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCIBE,
UNSUBACK。
SUBSCRIBE, UNSUBSCRIBE 和 PUBLISH(QoS 大于 0) 控制报文必须包含一个非零的 16 位报文标识
符(Packet Identifier) [MQTT-2.3.1-1]。客户端每次发送一个新的这些类型的报文时都必须分配一个当前
未使用的报文标识符 [MQTT-2.3.1-2]。 如果一个客户端要重发这个特殊的控制报文,在随后重发那个报文
时, 它必须使用相同的标识符。 当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。
QoS 1 的 PUBLISH 对应的是 PUBACK, QoS 2 的 PUBLISH 对应的是 PUBCOMP,与 SUBSCRIBE 或
UNSUBSCRIBE 对应的分别是 SUBACK 或 UNSUBACK [MQTT-2.3.1-3]。 发送一个 QoS 0 的 PUBLISH
报文时, 相同的条件也适用于服务端 [MQTT-2.3.1-4]。
QoS 设置为 0 的 PUBLISH 报文不能包含报文标识符 [MQTT-2.3.1-5]。
PUBACK, PUBREC, PUBREL 报文必须包含与最初发送的 PUBLISH 报文相同的报文标识符 [MQTT-2.3.1-
6]。 类似地, SUBACK 和 UNSUBACK 必须包含在对应的 SUBSCRIBE 和 UNSUBSCRIBE 报文中使用的
报文标识符 [MQTT-2.3.1-7]
PUBACK, PUBREC, PUBREL报文必须包含与最初发送的PUBLISH报文相同的报文标识符。类似地,SUBACK和UNSUBACK必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的报文标识符。
客户端和服务端彼此独立地分配报文标识符。因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换。
3.3、MQTT协议数据包-有效载荷
某些MQTT控制报文在报文的包含一个有效载荷
4、MQTT协议控制报文
4.1 、MQTT协议控制报文-CONNECT – 连接服务端
客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是 CONNECT 报文 [MQTT-
3.1.0-1]。在一个网络连接上,客户端只能发送一次 CONNECT 报文。服务端必须将客户端发送的第二个 CONNECT
报文当作协议违规处理并断开客户端的连接 [MQTT-3.1.0-2]。 有关错误处理的信息请查看 4.8 节。有效载荷包含一个或多个编码的字段。 包括客户端的唯一标识符, Will 主题, Will 消息, 用户名和密码。 除了客户端标识之外, 其它的字段都是可选的, 基于标志位来决定可变报头中是否需要包含这些字段。
同3、MQTT协议数据包格式 connect的报文格式 分为 固定报头,可变报头,有效载荷
4.1.1 CONNECT 报文的固定报头
![](https://i-blog.csdnimg.cn/blog_migrate/ca40489de4229d2170971dbd80d0d5de.png)
剩余长度字段
剩余长度等于可变报头的长度(10 字节) 加上有效载荷的长度。 编码方式见 3.1.3 节的说明。
4.1.2 CONNECT 报文的可变报头
CONNECT 报文的可变报头按下列次序包含四个字段:协议名(Protocol Name) , 协议级别(Protocol
Level) , 连接标志(Connect Flags)和保持连接(Keep Alive) 。
4.1.2.1 CONNECT 报文的可变报头-协议名
4.1.2.2 CONNECT 报文的可变报头-协议级别
4.1.2.3 CONNECT 报文的可变报头-连接标志
4.1.2.3.1 CONNECT 报文的可变报头-连接标志-will
遗嘱标志(Will Flag) 被设置为 1,表示如果连接请求被接受了, 遗嘱(Will Message) 消息必须被存储在
服务端并且与这个网络连接关联。之后网络连接关闭时,服务端必须发布这个遗嘱消息, 除非服务端收到
DISCONNECT 报文时删除了这个遗嘱消息 [MQTT-3.1.2-8] 。
遗嘱消息发布的条件, 包括但不限于:
服务端检测到了一个 I/O 错误或者网络故障。
客户端在保持连接(Keep Alive)的时间内未能通讯。
客户端没有先发送 DISCONNECT 报文直接关闭了网络连接。
由于协议错误服务端关闭了网络连接。
如果遗嘱标志被设置为 1,连接标志中的 Will QoS 和 Will Retain 字段会被服务端用到, 同时有效载荷中必
须包含 Will Topic 和 Will Message 字段 [MQTT-3.1.2-9]。
一旦被发布或者服务端收到了客户端发送的 DISCONNECT 报文, 遗嘱消息就必须从存储的会话状态中移
除 [MQTT-3.1.2-10]。
如果遗嘱标志被设置为 0, 连接标志中的 Will QoS 和 Will Retain 字段必须设置为 0, 并且有效载荷中不能
包含 Will Topic 和 Will Message 字段 [MQTT-3.1.2-11]。
如果遗嘱标志被设置为 0,网络连接断开时, 不能发送遗嘱消息 [MQTT-3.1.2-12]。
服务端应该迅速发布遗嘱消息。在关机或故障的情况下, 服务端可以推迟遗嘱消息的发布直到之后的重启。
如果发生了这种情况, 在服务器故障和遗嘱消息被发布之间可能会有一个延迟。
这两位用于指定发布遗嘱消息时使用的服务质量等级。
如果遗嘱标志被设置为 0, 遗嘱 QoS 也必须设置为 0(0x00) [MQTT-3.1.2-13]。
如果遗嘱标志被设置为 1, 遗嘱 QoS 的值可以等于 0(0x00), 1(0x01), 2(0x02)。 它的值不能等于 3
遗嘱保留----will retain
位置: 连接标志的第 5 位。
MQTT-3.1.1-CN 24
如果遗嘱消息被发布时需要保留,需要指定这一位的值。
如果遗嘱标志被设置为 0, 遗嘱保留(Will Retain) 标志也必须设置为 0 [MQTT-3.1.2-15]。
如果遗嘱标志被设置为 1:
如果遗嘱保留被设置为 0, 服务端必须将遗嘱消息当作非保留消息发布 [MQTT-3.1.2-16]。
如果遗嘱保留被设置为 1, 服务端必须将遗嘱消息当作保留消息发布 [MQTT-3.1.2-17]
4.1.2.3.2 CONNECT 报文的可变报头-连接标志-Clean Session
4.1.2.3.3 CONNECT 报文的可变报头-连接标志-Retain与Clean Session字段
关于clean session的说明:
如果终端设备离线之后,client connection的进程将销毁。
如果终端设备的clean session的值为true,那么它离线之后,会话将销毁,相应的session进程也会销毁。如果终端设备的 clean session的值为false,那么它离线之后,会话将得以保留,相应的session进程也仍然存在。
关于retain的说明:
retained_message终端设备publish消息时,如果retain值是true,则服务器会一直记忆,哪怕是服务器重启。因为Mnesia会本地持久化。
如果服务器接收到终端publish某主题的消息,payload为空且retain值是true,则会删除这条持久化的消息。如果服务器接收到终端publish某主题的消息,payload为空且retain值是false,则不会删除这条持久化的消息。
以上两点信息可以实现设备上线后理解收到发布过的信息。
4.1.2.3.4 CONNECT 报文的可变报头-连接标志-用户名标志
位置: 连接标志的第 7 位。
如果用户名(User Name) 标志被设置为 0, 有效载荷中不能包含用户名字段 [MQTT-3.1.2-18]。
如果用户名(User Name) 标志被设置为 1, 有效载荷中必须包含用户名字段 [MQTT-3.1.2-19]。
4.1.2.3.5 CONNECT 报文的可变报头-连接标志-密码标志
位置: 连接标志的第 6 位。
如果密码(Password) 标志被设置为 0, 有效载荷中不能包含密码字段 [MQTT-3.1.2-20]。
如果密码(Password) 标志被设置为 1, 有效载荷中必须包含密码字段 [MQTT-3.1.2-21]。
如果用户名标志被设置为 0, 密码标志也必须设置为 0 [MQTT-3.1.2-22]。
4.1.2.4 CONNECT 报文的可变报头-keeplive
保持连接(Keep Alive) 是一个以秒为单位的时间间隔,表示为一个 16 位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻, 两者之间允许空闲的最大时间间隔。 客户端负责保证控制报文发送的时间间隔不超过保持连接的值。 如果没有任何其它的控制报文可以发送, 客户端必须发送一个PINGREQ 报文 。
如果保持连接的值非零,并且服务端在一点五倍的保持连接时间内没有收到客户端的控制报文, 它必须断开客户端的网络连接, 认为网络连接已断开
保持连接的实际值是由应用指定的, 一般是几分钟。 允许的最大值是 18 小时 12 分 15 秒
4.1.2.5 CONNECT 报文的可变报头-总结
ClientId:broker内部唯一标示客户端的ID(CleanSession为true时可为空)
CleanSession:标示client和broker之间是否需要建立持久连接(CleanSession为false表示持久连接)
Username/Password:客户端验证(平文传输)
WillMessage:遗嘱消息
KeepAlive:客户端发起PING Request的时间间隔,确保连接正常。
4.1.2.6-CONNECT 报文的可变报头非规范示例
4.1.3 CONNECT 报文的有效载荷
CONNECT 报文的有效载荷(payload) 包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否
包含这些字段。 如果包含的话, 必须按这个顺序出现:客户端标识符, 遗嘱主题, 遗嘱消息, 用户名, 密
码
抓包分析https://blog.csdn.net/qq_41538097/article/details/107963579
4.2 、MQTT协议控制报文-CONNACK – 确认连接请求
服务端发送 CONNACK 报文响应从客户端收到的 CONNECT 报文。服务端发送给客户端的第一个报文必
须是 CONNACK [MQTT-3.2.0-1]。
如果客户端在合理的时间内没有收到服务端的 CONNACK 报文, 客户端应该关闭网络连接。 合理 的时间取
决于应用的类型和通信基础设施。
4.2.1 MQTT协议控制报文-CONNACK – 确认连接请求-固定报头
4.2.2 MQTT协议控制报文-CONNACK – 确认连接请求-可变报头
4.2.3 MQTT协议控制报文-CONNACK – 确认连接请求-有效载荷
CONNACK 报文没有有效载荷。
4.3 、MQTT协议控制报文-PUBLISH – 发布消息
基本与CONNECT 相同 略,请查看链接
4.4 、MQTT协议控制报文-PUBACK –发布确认
基本与CONNECT 相同 略,请查看链接
4.5 、MQTT协议控制报文-PUBREC – 发布收到(QoS 2, 第一步)
基本与CONNECT 相同 略,请查看链接
4.6 、MQTT协议控制报文-PUBREL – 发布释放(QoS 2, 第二步)
基本与CONNECT 相同 略,请查看链接
4.7、 MQTT协议控制报文-PUBCOMP – 发布完成(QoS 2, 第三步)
基本与CONNECT 相同 略,请查看链接
4.8 、MQTT协议控制报文-SUBSCRIBE - 订阅主题
基本与CONNECT 相同 略,请查看链接
4.9 、MQTT协议控制报文-SUBACK – 订阅确认
基本与CONNECT 相同 略,请查看链接
4.10 、MQTT协议控制报文-UNSUBSCRIBE –取消订阅
基本与CONNECT 相同 略,请查看链接
4.11 、MQTT协议控制报文-UNSUBACK – 取消订阅确认
基本与CONNECT 相同 略,请查看链接
4.12、MQTT协议控制报文-PINGREQ – 心跳请求
基本与CONNECT 相同 略,请查看链接
4.13、MQTT协议控制报文-PINGRESP – 心跳响应
基本与CONNECT 相同 略,请查看链接
4.14、MQTT协议控制报文-DISCONNECT –断开连接
基本与CONNECT 相同 略,请查看链接
链接地址:
https://download.csdn.net/download/caofengtao1314/12500818
https://download.csdn.net/download/caofengtao1314/12500842