一、什么是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级别等标志位。第二个字节开始是剩余长度字段,该长度是后面的可变报文头加上消息负载的总长度。
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代理,以此来提供网络传输的安全性。