MQTT简介之二 MQTT协议

1、什么是MQTT

MQTT 协议( Message Queuing Telemetry Transport ),翻译过来 就是消息队列遥测传输, IBM 公司于 1999 年提出的
MQTT 是一个基于 TCP 的发布订阅协议,它被设计用于轻量级的发布 / 订阅式消息传输 , 旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。 MQTT 是专门针对物联网开发的轻量级传输协议。 MQTT 协议针对低带宽网络 , 低计算能力的设备 , 做了特殊的优化 , 使得其能适应各种物联网应用场景。
2014 年发布最新版本是 3.1.1
2019 年发布最新版本是 5.0
 

1.1、MQTT特点 

MQTT工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特征:

1. 使用的发布/订阅消息模式,它提供了一对多消息分发,以实现与应用程序的解耦。
2. 对负载内容屏蔽的消息传输机制。
3. 使用 TCP/IP 提供网络连接
4. 对传输消息有三种服务质量(QoS):
最多一次,这一级别会发生消息丢失或重复,消息发布依赖于底层TCP/IP网络。即:<=1
至多一次,这一级别会确保消息到达,但消息可能会重复。即:>=1
只有一次,确保消息只有一次到达。即:=1。在一些要求比较严格的计费系统中,可以使用此级 5
5. 数据传输和协议交换的最小化(协议头部只有2字节),以减少网络流量
6. 通知机制,异常中断时通知传输双方

1.2、MQTT协议原理-协议实现方式 

      

实现MQTT协议需要:客户端和服务器端
MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
MQTT传输的消息分为:主题(Topic)和负载(payload)两部分
Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload)
payload,可以理解为消息的内容,是指订阅者具体要使用的内容

 

2、MQTT协议原理-网络传输与应用消息 

MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。
当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。
 

2.1、MQTT协议原理-客户端 

       一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:

发布其他客户端可能会订阅的信息
订阅其它客户端发布的消息
退订或删除应用程序的消息
断开与服务器连接

2.2、MQTT协议原理-服务端 

MQTT服务器以称为“消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:接受来自客户的网络连接

接受客户发布的应用信息

处理来自客户端的订阅和退订请求

向订阅的客户转发应用程序消息

2.3、MQTT协议原理-订阅、主题、会话

订阅(Subscription)

     订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。

会话(Session)

     每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。

主题名(Topic Name)

     连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。

主题筛选器(Topic Filter)

     一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。

负载(Payload)

     消息订阅者所具体接收的内容

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

如果DUP标志设置为0,则表示这是客户端或服务器首次尝试发送此MQTT PUBLISH数据包。如果DUP标志设置为1,则表示这可能是先前尝试发送数据包的重新传递。
当客户端或服务器尝试重新发送PUBLISH数据包时,DUP标志必须设置为1。 对于所有QoS 0消息,DUP标志必须设置为0。
当PUBLISH数据包由服务器发送给订户时,不会传播来自传入PUBLISH数据包的DUP标志的值。输出PUBLISH数据包中的DUP标志独立于输入PUBLISH数据包设置,其值必须仅由输出PUBLISH数据包是否为重传确定。
包含DUP标志设置为1的控制数据包的接收者不能假定它已经看到该数据包的早期副本。
 
 

 3.1.2.2、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-服务质量等级 QOS

       

3.1.2.3、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-will遗言 

         will遗言虽然不属于指定控制报文类型的标志位,但是和Retain是相关的

 • 包括 Will topic 、will message 、 will Qos、will retain。
 • 一个Client异常断开连接的时候或者Server处理失败的时候,Server会把Client的will信息,当做Publish处理,Publish的topic 就是Will topic,消息就是will message。如果Client发送了disconnect来断开连接,则Server就会清除will信息,不会把will当Publish处理。
 

3.1.2.3、MQTT协议数据包-固定报头-用于指定控制报文类型的标志位-Retain

Retain 表示 Publish 的消息,会保留在 Broker上,一旦有其他新的连接上来,并且subscribe了对应的消息,会立刻Publish这个Retain的消息。且回复给订阅者的的这个Publish也会携带Retain标志位。
MQTT规范上说,这个功能,对于发布的消息是自己状态的话,就很有用。
由于Will消息中也携带retain,且Will消息本身会也当做Publish,所以Retain的效果也作用于will,也就是说携带Retain的Will消息会被Server保留,且对于新连接,同样也会尝试去publish(如果topic匹配)。
其次,Client可以多次通过发送Retain标志位的Publish,来更新Server保存的Publish消息,当然Server是保留client发送的所有的Retain消息的,而不是覆盖之前你的Retain,不过回复订阅者的是最新消息(我不是很理解MQTT为什么要保留老的,既然发送给客户端的永远是最新的那个)。
Client可以通过发送Retain标志位的,且没有message的Publish,来告知Server删除这个Retain消息,注意,是清空所有该topic的消息。
Client可以通过发送Retain标志位的,Qos为0的Publish,来告知Server删除对应Topic的所有Retain消息,且保留当前这个消息为Retain的消息。
 
 

3.1.3、MQTT协议数据包-固定报头-剩余长度

使用变成编码(14个字节表示,即最大可表示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 报文的固定报头

剩余长度字段
剩余长度等于可变报头的长度(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 topic 、will message 、 will Qos、will retain。
一个Client异常断开连接的时候或者Server处理失败的时候,Server会把Client的will信息,当做Publish处理,Publish的topic就是Will topic,消息就是will message。如果Client发送了disconnect来断开连接,则Server就会清除will信息,不会把will当Publish处理。
遗嘱 标志---will Flag
位置: 连接标志的第 2 位。
遗嘱标志(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]。
服务端应该迅速发布遗嘱消息。在关机或故障的情况下, 服务端可以推迟遗嘱消息的发布直到之后的重启。
如果发生了这种情况, 在服务器故障和遗嘱消息被发布之间可能会有一个延迟。
 
 
遗嘱 QoS---will Qos
位置: 连接标志的第 4 和第 3 位。
这两位用于指定发布遗嘱消息时使用的服务质量等级。
如果遗嘱标志被设置为 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

如果Connect 帧的CleanSession为0,则Server会查找保存上次该客户端连接过来的Session,session里面保存了之前Client携带的所有的订阅topic等,如果Server找到了session,会在Connect Ack中把session present置1,否则置0。换句话说,如果成功用老的会话,Client不需要重新订阅之前的Topic。
CleanSession的另一个好处就是Server保留了Qos信息,例如,假设Client上次收到Publish消息,但是还没来得及回复Publish ack或者Publish recvive就挂了,Server知道Client还没处理,会在Client第二次连接完成后立刻再次发送Publish消息。(前提是Client的CleanSession为1,且Server找到了Session)。
 

4.1.2.3.3 CONNECT 报文的可变报头-连接标志-RetainClean 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

 

 

 

 

 

 

 

 
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值