一、什么是MQTT?

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于订阅和发布(Publish/Subscribe)模式的轻量级通讯协议。它承载在TCP/IP协议上,适用于在嵌入式这种硬件资源不是很丰富的情况下(有限的网络带宽)提供实时可靠的通讯服务。MQTT在物联网、嵌入式设备、移动应用等场景有广泛的应用。

MQTT是属于应用层协议,运行于TCP之上。

MQTT协议特点:
0、使用发布/订阅消息模式,它提供了一对多消息发布,以实现与应用程序解耦
1、协议需要两个角色:客户端和服务器
2、MQTT是基于TCP长连接,首先需要跟MQTT服务器建立TCP连接,然后发送登录请求,要保持长连接,还要定时发送心跳包和服务器保持连接。
3、MQTT协议有三种身份:发布者(publish)、代理(Broker)、订阅者(Subscribe)。使用发布/订阅消息模式,继而支持一对多的发布形式。
发布者和订阅者可以看作是客户端,代理看成是服务端,消息发布者可以同时是订阅者。
4、数据传输和协议交换的最小化(协议头部只有2字节),以减少网络流量通知机制,
5 、 通知机制,异常中断时通知传输双方

二、MQTT消息格式

消息格式为
固定报头|可变报头|有效负载

固定报头:

固定报头最少有两个字节,第一个字节包含消息类型(Message Type)和Qos级别等标志位。第二个字节开始是剩余长度字段,该长度是后面的可变报文头加上消息负载的总长度。

androidmqtt协议 mqtt协议应用_服务器


Message Type: 消息类型,取值范围(1-14,0和15保留)

Dup Flag: 用来保证消息可靠传输的,如果设置为1,则下面的变长头部里多加Messageid,并需要回复确认,保证消息传输完成,但不能用于检测消息重复发送。

Qos Level :用于服务质量保证,下面有详细介绍

Retain:主要用于PUBLISH的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果不设置该位那么推送至当前订阅的就释放了。

下面详细说下消息的各个字段

固定报文头中的第一个字节包含消息类型(Message Type),mqtt协议有14种不同的消息类型,简单分为连接与终止、发布和订阅、Qos消息的机制和各种确认ACK。

类型名称         类型值     流动方向              报文说明
Reserved          0          禁止                保留
CONNECT           1        客户端到服务器         发起连接请求
CONNACK           2        服务器到客户端         连接确认
PUBLISH           3        两个方向都允许         发布消息
PUBACK            4        两个方向都允许         Qos1消息确认
PUBREC            5        两个方向都允许         Qos2消息回执(保证交互第一步)
PUBREL            6        两个方向都允许         Qos2消息释放(保证交互第二步)
PUBCOMP           7        两个方向都允许         Qos2消息完成(保证交互第三步)
SUBSCRIBE         8        客户端到服务器         订阅请求
SUBACK            9        服务器到客户端         订阅确认
UNSUBSCRIBE       10       客户端到服务器         取消订阅
UNSUBACK          11       服务器到客户端         取消订阅确认
PINGREQ           12       客户端到服务器         心跳请求
PINGRESP          13       服务器到客户端         心跳响应
DISCONNECT        14       客户端到服务器         断开连接
Reserved          15       禁止                  保留

消息服务质量(Qos)
MQTT消息质量有三个等级,Qos0,Qos1,Qos2

最多分发一次(Qos0):消息最多分发一次,消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试,消息要么只会到达服务端一次,要么完全没有到达。

Qos1:至少分发一次,服务器的而消息接收由PUBACK进行确认,如果通信链路故障或者发送设备异常,或者在指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了DUP位的消息

Qos2:只分发一次。这里是最高级别的消息传递,消息丢失和重复都是不可以接受的,使用这个服务质量等级会有额外的开销。使用与实时计费系统。

可变报头

协议名(Protocol Name)、协议级别(Protocol Level)、连接标志(Connect Flags)和心跳时间间隔(Keep Alive Timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等。

连接标志位字段(Connect Flags):
在可变报文头的连接标志位字段(Connect Flags)里有三个Will标志位:clean session、will flag、will Qos、Will Retain Flag,这些Will字段用于监管客户端与服务器之间的连接状态。

clean session: 0表示如果订阅的客户端因为某种原因断线了,那么要保存其推送的消息,如果其重连的话则将这些消息推送。1表示消除,表示客户端是第一次连接
will flag: 该位设置为1,要求重传(如果客户端在断线前发送了DISCONNECT中断连接消息则不会重传消息)。并且下面的will qos、will retain也要设置,消息体中的Topic和MessageID也要设置,就是表示发生了错误要重传。
will Qos: 在CONNECT非正常情况下设置,一般如果标识了WillFlag,那么这个位置也要标识
will RETAIN:同在CONNECT中,如果标识了will flag也要标识该位。

username flag和password flag:用来标识是否在消息体中传递用户和密码,只有标识了,消息体中的用户名和密码才有效,只标识密码而不标记用户名是不合法的。

使用场景:服务器与客户端通信时,当遇到异常或客户端心跳超时的情况,MQTT服务器会替客户端发布一个Will消息。当然如果服务器收到来自客户端的DISCONNECT消息,则不会出发will消息的发送。因此,will字段可以应用于设备掉线后需要通知用户的场景。

连接保活心跳机制(Keep Alive Timer)
MQTT客户端可以设置一个心跳时间间隔(Keep Alive Timer),表示在每个心跳间隔时间内发送一条消息,如果在这个时间周期内,没有业务数据相关的消息,客户端就会发送一个PINGREQ消息,相应的,服务器就会返回一个PINGRESP消息进行确认。如果服务器在1.5心跳周期内没有收到来自客户端的消息,就会断开与客户端的连接。最大心跳间隔周期可设置为18h,0意味着客户端不断开。

connect return code :通常哟宏宇CONNACK消息中表示返回的连接情况,通过return code验证连接情况( 0:连接成功 1 连接拒绝 …)

topic name:订阅消息标识,主要用于PUBLISH和SUBSCRIBE消息中,最大可支持32767个字符,即4个字节。

有效负载(Payload)

消息主题(body)
当MQTT发送的消息类型是CONNECT、PUBLISH、SUBSCRIBE、SUBACK、UNSUBSCRIBE时,则会带有负荷。

三、MQTT的安全设计考虑

背景:由于MQTT运行于TCP层之上并以明文方式传输,使用wireshark可以完全看到MQTT发送的所有消息。所以会一定的安全风险,安全功能可以从三个层次来考虑——应用层、传输层、网络层

应用层:mqtt提供了客户端标识(Client Identifier)以及用户名和密码,可以在应用层验证设备。(mqtt通过connect消息的username和password、客户端标识等字段发送信息 )

传输层:类似于https,mqtt基于tcp连接,也可以加上一层TLS,可以防止中间人攻击。客户端证书不但可以作为设备的身份凭证,还可以用来验证设备。

网络层:条件允许的话可以拉专线(VPN)来连接设备与MQTT代理,以此来提供网络传输的安全性。