MQTT协议设计简介
简介
MQTT全称为MQ Telemetry Transport,它是一种轻量级的基于订阅分发的消息协议,适用于慢网络和嵌入式设备通信。MQTT支持一对多的消息分发,提供QoS以保证消息的准确到达,使用TCP作为传输层协议,当前比较流行的版本是3.1。
如今业界已经有很多公司在使用MQTT来构建应用,比如国外的facebook,国内也有很多,比如提供第三方push的云巴等。
MQTT协议设计的比较简洁,没有什么冗余的东西,相信这也是很多公司愿意尝试使用它的原因,至少学习起来并不费太大功夫。
消息设计
MQTT协议的消息最多由两部分构成:固定头部、可变头部和负载。
(1)固定头部MSB;由两个字节构成,第一个字节包含4位消息类型、1位DUP标识、2位Qos等级和1位保留位,第二个字节保存了消息的剩余长度。
MQTT消息类型只有4位来标识,意味着最多不会超过16种,实际上MQTT协议定义了14种消息类型,还有两种是保留类型。简单列举下:
CONNECT(1,连接请求)
CONNACK(2,连接ACK)
PUBLISH(3,发布消息)
PUBACK(4,发布ACK)
PUBREC(5,发布已接受)
PUBREL(6,发布释放)
PUBCOMP(7,发布完成)
SUBSCRIBE(8,订阅)
SUBACK(9,订阅ACK)
UNSUBSCRIBE(10,取消订阅)
UNSUBACK(11,取消订阅ACK)
PINGREQ(12,PING请求)
PINGRESP(13,PING响应)
DISCONNECT(14,断开连接)
DUP标识表示客户端或服务端尝试重发消息(包括PUBLISH、PUBREL、SUBSCRIBE和UNSUBSCRIBE四类消息),如果置为1表示该消息需要进行确认,此时QoS值大于0,且可变头部里需要包含消息ID(16位无符号整型、由客户端维护)。
虽然MQTT协议采用了TCP协议作为传输层来保证报文的可靠性,但为了确保消息能正常被应用接收到,MQTT协议提供了QoS机制,分三种等级:0表示最多发送一次、1表示至少发送一次、2表示确定只有一次。目前QoS只适用于PUBLISH类型。
保留标识也只适用于PUBLISH类型,如果置为1表示服务端需要保存消息直到被订阅者接收。
头部第二个字节保存了消息的剩余长度,包括可变头部和负载的总长度。8位剩余长度由两部分构成:前7位记录消息长度,第8位表示是否还有延续,用来处理长度超过127字节的消息。
MQTT协议严格定义了剩余长度最长为256MB,最长可以用4个字节来表示剩余长度。
具体表示范围:用1个字节表示长度从0(0x00)到127(0x7F),2个字节表示长度从128(0x80,0x01)到16383(0xFF,0x7F),3个字节表示长度从16384(0x80,0x80,0x01)到2097151(0xFF,0xFF,0x7F),4个字节表示长度从2097152(0x80,0x80,0x80,0x01)到268435455(0xFF,0xFF,0xFF,0x7F)。
下面是长度X编码的算法:
do
digit = X MOD 128
X = X DIV 128
// if there are more digits to encode, set the top bit of this digit
if ( X > 0 )
digit = digit OR 0x80
endif
'output' digit
while ( X> 0 )
解码算法:
multiplier = 1
value = 0
do
digit = 'next digit from stream'
value += (digit AND 127) * multiplier
multiplier *= 128
while ((digit AND 128) != 0)
协议规定剩余长度包含在固定头部中,不计入可变头部,意味着固定长度最少为2个字节,最大为5个字节。
(2)可变头部;可变头部包含有多种信息,规定以以下顺序来保存:
协议名称:协议名称会出现在CONNECT类型消息中,保存的是一串UTF-8编码的字符串"MQIsdp"。
协议版本号:同样也出现在CONNECT类型消息中,记录客户端当前所使用的MQTT协议版本号,如最新的是3(0x03)。
连接标识:包括清空会话、Will、Will QoS和Will retain标识,均会出现在CONNECT类型消息中。简单说明下几个标识的含义:
a、清空会话置为1表示服务端会清空客户端以前的所有信息,置为0表示服务器会保存客户端的状态信息,即使客户端断开连接,服务器会保存QoS为1或2的消息,当客户端重连(清空会话置为0)时服务器会将订阅的消息发送给客户端。
b、Will消息:当服务端与客户端通信时发生I/O错误,或客户端没有在keep alive时间内与服务端通信,此时服务器会向客户端发送Will消息。而当客户端向服务端发送DISCONNECT消息时,服务器不会向客户端发送此类消息。
一旦连接标示中设置了Will标识,Will QoS和Will Retain字段也必须设置。Will QoS用来定义Will消息的QoS等级,Will Retain定义服务器是否保留消息,Will消息包含在CONNECT消息的负载中。
用户名和密码标识,客户端与服务端进行连接时可以提供用户名和密码来验证。当设置了用户名标示时,需要提供用户名信息;若设置了密码标示,则需要指定密码。
Keep Alive定时器出现在CONNECT消息可变头部中,它定义了从客户端收到消息的最大时间间隔,使得服务端不需要等待TCP/IP超时,根据时间间隔来检测客户端是否已断开连接。客户端有义务在该时间段内向服务器发送消息,若没有待发的数据,客户端需要发送PINGREQ消息,等待服务器的PINGRESP消息。
Keep Alive定时器由2个字节构成,存储了最大时间间隔数值。
连接返回代码出现在CONNACK消息可变头部中,由1个字节构成,客户端根据返回代码可以知道是否与服务器连接成功,如果失败也可以知道失败当具体原因。
0x00表示连接成功、0x01表示不支持客户端协议版本号、0x02表示拒绝标示符、0x03表示服务器不可用、0x04表示用户名密码有误、0x05表示未授权。
topic名称,表示数据所发往的信道标识。
(3)负载;CONNECT、SUBSCRIBE和SUBACK消息均包含负载。
CONNECT负载包括客户端唯一ID、也可能包括Will topic、Will消息、用户名和密码。
SUBSCRIBE包含所订阅的topic名称列表,以及QoS等级。
SUBACK包含允许的QoS等级列表。