MOTT协议
MQTT是什么?
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(Publish/Subscribe)模式的轻量级通讯协议。
该协议构建于TCP/IP协议上,由IBM在1999年发布。
MQTT最大的优点在于可以以极少的代码和有限的带宽,为远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,在物联网、小型设备、移动应用等方面有广泛的应用。
MQTT是哪一层的协议?
MQTT协议运行于TCP之上,属于应用层协议,因此只要是支持TCP/IP协议栈的地方,都可以使用MQTT。
(TCP/IP参考模型可以分为四层:应用层、传输层、网络层、链路层。)
MQTT消息格式
每条MQTT命令消息的消息头都包含一个固定的报头,有些消息会携带一个可变报文头和一个负荷。
消息格式如下:
固定报文头 | 可变报文头 | 负荷(报文体)
-
固定报文头(Fixed Header)
MQTT固定报文头最少有两个字节,第一字节包含消息类型(Message Type)和QoS级别等标志位。第二字节开始是剩余长度字段,该长度是后面的可变报文头加消息负载的总长度,该字段最多允许四个字节。
剩余长度字段单个字节最大值为二进制0b0111 1111,16进制0x7F。也就是说,单个字节可以描述的最大长度是127字节。为什么不是256字节呢?因为MQTT协议规定,单个字节第八位(最高位)若为1,则表示后续还有字节存在,第八位起“延续位”的作用。
例如,数字64,编码为一个字节,十进制表示为64,十六进制表示为0×40。数字321(65+2*128)编码为两个字节,重要性最低的放在前面,第一个字节为65+128=193(0xC1),第二个字节是2(0x02),表示2×128。
由于MQTT协议最多只允许使用四个字节表示剩余长度(如表1),并且最后一字节最大值只能是0x7F不能是0xFF,所以能发送的最大消息长度是2的28次方=256MB.
-
可变报文头(Variable Header)
可变报文头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等。 -
有效负荷(Payload)
有效负荷即是消息主体(body)。
当MQTT发送的消息类型是CONNECT(连接)、PUBLISH(发布)、SUBSCRIBE(订阅)、SUBACK(订阅确认)、UNSUBSCRIBE(取消订阅)时,则会带有负荷。
MQTT的主要特性
-
MQTT的消息类型(Message Type)
MQTT的消息类型
固定报文头中的第一个字节包含连接标志(Connect Flags),连接标志用来区分MQTT的消息类型。
MQTT协议拥有14种不同的消息类型,可简单分为连接及终止、发布和订阅、QoS 2消息的机制以及各种确认ACK。
-
消息质量(QoS)
MQTT消息质量有三个等级,QoS 0,QoS 1和 QoS 2。 -
QoS 0:最多分发一次。消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试,消息要么只会到达服务端一次,要么根本没有到达。
-
QoS 1:至少分发一次。服务器的消息接收由PUBACK消息进行确认,如果通信链路或发送设备异常,或者指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了DUP位的消息。
-
QoS 2:只分发一次。这是最高级别的消息传递,消息丢失和重复都是不可接受的,使用这个服务质量等级会有额外的开销。
应用举例:共享单车,使用QoS 0发送单车的当前位置,QoS 1进行单车解锁操作,QoS 2进行支付。 -
遗愿标志(Will Flag)
在可变报文头的连接标志位字段(Connect Flags)里有三个Will标志位:Will Flag、Will QoS和Will Retain Flag,这些Will字段用于监控客户端与服务器之间的连接状况。如果设置了Will Flag,就必须设置Will QoS和Will Retain标志位,消息主体中也必须有Will Topic和Will Message字段。
那遗愿消息是怎么回事呢?服务器与客户端通信时,当遇到异常或客户端心跳超时的情况,MQTT服务器会替客户端发布一个Will消息。当然如果服务器收到来自客户端的DISCONNECT消息,则不会触发Will消息的发送。
因此,Will字段可以应用于设备掉线后需要通知用户的场景。 -
心跳机制(Keep Alive Timer)
MQTT客户端可以设置一个心跳间隔时间(Keep Alive Timer),表示在每个心跳间隔时间内发送一条消息。如果在这个时间周期内,没有业务数据相关的消息,客户端会发一个PINGREQ消息,相应的,服务器会返回一个PINGRESP消息进行确认。如果服务器在一个半(1.5)心跳间隔时间周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值大约可以设置为18个小时,0值意味着客户端不断开。 -
异步发布/订阅实现
发布/订阅模式解耦了发布消息的客户(发布者)与订阅消息的客户(订阅者)之间的关系,这意味着发布者和订阅者之间并不需要直接建立联系。
发布者设定一个发布主题,订阅者可以订阅某个主题,然后发布者对该主题发布消息,订阅者收到消息后即可进行一系列操作。 -
二进制格式实现
MQTT基于二进制实现而不是字符串,MQTT固定报文头仅有两字节,所以相比其他协议,发送一条消息最省流量。
(HTTP和XMPP都是基于字符串实现,拥有冗长的协议头部。) -
MQTT的安全
MQTT运行于TCP层之上并以明文方式传输,作为传输协议,MQTT仅关注消息传输。安全性由具体的开发者提供保障。
全功能可以从三个层次来考虑——应用层、传输层、网络层。 -
应用层:在应用层上,MQTT提供了客户标识(Client Identifier)以及用户名和密码,可以在应用层验证设备。
-
传输层:类似于HTTPS,MQTT基于TCP连接,也可以加上一层TLS,传输层使用TLS加密是确保安全的一个好手段,可以防止中间人攻击。客户端证书不但可以作为设备的身份凭证,还可以用来验证设备。
-
网络层:如果有条件的话,可以通过拉专线或者使用VPN来连接设备与MQTT代理,以提高网络传输的安全性。
-
认证
-
应用层:MQTT支持客户标识、用户名和密码认证;
-
传输层:传输层可以使用TLS,除了加密通讯,还可以使用X509证书来认证设备。
-
客户标识
MQTT客户端可以发送最多65535个字符作为客户标识(Client Identifier),一般来说可以使用嵌入式芯片的MAC地址或者芯片序列号。虽然使用客户标识来认证可能不可靠,但是在某些封闭环境或许已经足够了。 -
用户名和密码
MQTT协议支持通过CONNECT消息的username和password字段发送用户名和密码。
一般来说,使用客户标识、用户名和密码已经足够了,如果感觉还不够安全,还可以在传输层进行认证。
在传输层认证是这样的:MQTT代理在TLS握手成功之后可以继续发送客户端的X509证书来认证设备,如果设备不合法便可以中断连接。使用X509认证的好处是,在传输层就可以验证设备的合法性,在发送CONNECT消息之前便可以阻隔非法设备的连接,以节省后续不必要的资源浪费。而且,MQTT协议运行在使用TLS时,除了提供身份认证,还可以确保消息的完整性和保密性。
选择报文内容格式
MQTT协议只实现了传送消息的格式,并没有限制用户协议需要按照一定的风格,因此在MQTT协议之上,我们需要定义一套自己的通信协议。MQTT协议只实现了传送消息的格式,并没有限制用户协议需要按照一定的风格,因此在MQTT协议之上,我们需要定义一套自己的通信协议。
比如说,发布者向设备发布一条打开消息,设备可以回复一个消息并携带返回码,这样的消息格式是使用二进制、字符串还是JSON格式呢?
参考引用:https://blog.csdn.net/anxianfeng55555/article/details/80908795