MQTT V31协议规范中文版.docx
《MQTT V31协议规范中文版.docx》由会员分享,可在线阅读,更多相关《MQTT V31协议规范中文版.docx(43页珍藏版)》请在冰豆网上搜索。
MQTTV31协议规范中文版
作者:
∙InternationalBusinessMachinesCorporation(IBM)
∙Eurotech
翻译:
明歌
协议原文:
摘要
MQ遥测传输(MQTelemetryTransport,MQTT)是一个轻量级的基于代理的发布/订阅式消息传输协议,它的设计目标是开放、简单、轻量和易于实现。
这些特征使它适用于各种受限环境,比如,但不限于:
∙网络代价昂贵,低带宽或不可靠。
∙在嵌入设备中运行,处理器和内存资源有限。
该协议的特性包括:
∙使用发布/订阅消息模式,提供一对多的消息分发,解除应用程序耦合。
∙消息传输对有效载荷内容不可知。
∙使用TCP/IP提供基础网络连接。
∙有3个消息发布服务质量级别:
▪“至多一次”,消息发布完全依赖于底层TCP/IP网络。
消息有可能丢失或重复。
这一级别可应用于如下情景,如环境传感器数据,丢失一次读记录无所谓,因为很快下一次读记录就会产生。
▪“至少一次”,确保消息到达,但消息重复有可能发生。
▪“只有一次”,确保消息到达且只到达一次。
这一级别可用于如计费系统等场景,在计费系统中,消息丢失或重复可能会导致生成错误的费用。
∙轻量传输,开销很小(固定头部的长度只有2字节),协议交换最小化,以降低网络流量。
∙提供一种机制,当客户端异常中断时,利用LastWill和Testament特性来通知有关各方。
版权声明
©1999-2010Eurotech,InternationalBusinessMachinesCorporation(IBM).Allrightsreserved.
PermissiontocopyanddisplaytheMQTelemetryTransportspecification(the"Specification"),inanymediumwithoutfeeorroyaltyisherebygrantedbyEurotechandInternationalBusinessMachinesCorporation(IBM)(collectively,the"Authors"),providedthatyouincludethefollowingonALLcopiesoftheSpecification,orportionsthereof,thatyoumake:
AlinkorURLtotheSpecificationatoneoftheAuthors'websites.ThecopyrightnoticeasshownintheSpecification.TheAuthorseachagreetograntyouaroyalty-freelicense,underreasonable,non-discriminatorytermsandconditionstotheirrespectivepatentsthattheydeemnecessarytoimplementtheSpecification.THESPECIFICATIONISPROVIDED"ASIS,"ANDTHEAUTHORSMAKENOREPRESENTATIONSORWARRANTIES,EXPRESSORIMPLIED,INCLUDING,BUTNOTLIMITEDTO,WARRANTIESOFMERCHANTABILITY,FITNESSFORAPARTICULARPURPOSE,NON-INFRINGEMENT,ORTITLE;THATTHECONTENTSOFTHESPECIFICATIONARESUITABLEFORANYPURPOSE;NORTHATTHEIMPLEMENTATIONOFSUCHCONTENTSWILLNOTINFRINGEANYTHIRDPARTYPATENTS,COPYRIGHTS,TRADEMARKSOROTHERRIGHTS.THEAUTHORSWILLNOTBELIABLEFORANYDIRECT,INDIRECT,SPECIAL,INCIDENTALORCONSEQUENTIALDAMAGESARISINGOUTOFORRELATINGTOANYUSEORDISTRIBUTIONOFTHESPECIFICATION.
ThenameandtrademarksoftheAuthorsmayNOTbeusedinanymanner,includingadvertisingorpublicitypertainingtotheSpecificationoritscontentswithoutspecific,writtenpriorpermission.TitletocopyrightintheSpecificationwillatalltimesremainwiththeAuthors.
Nootherrightsaregrantedbyimplication,estoppelorotherwise.
1.简介
∙1.1 V3.1与V3之间的变化
2.消息格式
∙2.1 固定头部
∙2.2 可变头部
∙2.3 有效载荷
∙2.4 消息标识符
∙2.5 MQTT和UTF-8
∙2.6 未使用的位
3.命令消息
∙3.1 CONNECT
∙3.2 CONNACK
∙3.3 PUBLISH
∙3.4 PUBACK
∙3.5 PUBREC
∙3.6 PUBREL
∙3.7 PUBCOMP
∙3.8 SUBSCRIBE
∙3.9 SUBACK
∙3.10 UNSUBSCRIBE
∙3.11 UNSUBACK
∙3.12 PINGREQ
∙3.13 PINGRESP
∙3.14 DISCONNECT
4.消息流
∙4.1 交付质量级别和消息流
∙4.2 消息重传
∙4.3 消息排序
5.附录A主题通配符
1.简介
该协议规范主要分为3个主要部分:
∙对所有类型的数据包都通用的消息格式
∙每种特定数据包的具体细节
∙数据包如何在服务器和客户端之间传输
在附录中将介绍如何主题通配符(topicwildcards)的使用方法。
1.1V3.1与V3之间的变化
MQTTV3.1中与MQTTV3之间的不同点如下所示:
∙添加用户验证,用户名和密码现在可以在CONNECT数据包中一并发送。
∙为解决一些安全问题,在CONNACK数据包中添加了新的返回码。
∙当客户端发送未授权的PUBLISH或SUBSCRIBE命令时,客户端不会收到相应的通知,即客户端不知道命令不会被执行。
而且即使命令未被执行,该MQTT流也应该正常完成。
∙MQTT中的字符串现在支持完整的UTF-8字符集,而不仅仅是US-ASCII子集。
V3.1中,通过CONNECT包传送的协议版本号仍然是“3”,与V3相比没有变化。
现存的基于MQTTV3的服务器实现须通过正确考虑“剩余长度(RemainingLength)字段”,以及相应地忽略多余的安全信息来接受来自V3.1协议的客户端的连接。
2.消息格式
每个MQTT命令消息的消息头部都包含了一个固定头部。
其中一些类型的消息可能还需要一个可变头部和一个有效载荷(可理解为消息体)。
消息头部的具体格式将在后面章节中进行详细介绍。
2.1固定头部(Fixedheader)
每个MQTT命令消息的消息头部都包含一个固定头部。
固定头部的格式如下表如示。
Byte1
包含消息类型和标志(包括DUP,QoSlevel和RETAIN)字段。
Byte2
包含剩余长度字段(至少1个字节,最多4个字节)。
以下章节将详细介绍这些字段。
所有数据的值都是以big-endian(大端)模式存储:
数据的高位字节存放在内存的低地址中,数据的低位字节存放在内存高地址中。
一个16位字在内存中的存放顺序是先最高有效位(MSB),然后再最低有效位(LSB)。
消息类型(MessageType)
位置:
byte1,bits7-4
该字段为4-bit无符号值。
当前协议版本中该字段的具体枚举值如下表所示。
0:
保留
1:
客户端请求连接服务器
2:
连接确认
3:
发布消息
4:
发布确认
5:
发布接收(有保证的交付第1部分)
6:
发布释放(有保证的交付第2部分)
7:
发布完成(有保证的交付第3部分)
8:
客户端订阅请求
9:
订阅确认
10:
客户端取消订阅请求
11:
取消订阅确认
12:
PING请求
13:
PING回复
14:
客户端断开连接
15:
保留
标志位(Flags)
固定头部第1个字节中剩余的部分包含DUP,QoS和RETAIN标志字段。
相应bit位置如下表所示。
DUP
位置:
byte1,bit3
当客户端或服务器试图重发PUBLISH、PUBREL、SUBSRIBE、UNSUBSCRIBE消息时,该标志位要被置位(即设为1)。
这适用于消息的QoS标志值大于0的情况,此时消息确认是必需的。
当DUP位被置位时,可变头部将包含一个消息ID。
消息的接收者应当将该标志视为该消息之前可能已收到的提示消息,而不该依赖于它进行消息重复检测。
QoS
位置:
byte1,bits2-1
该标志位标明PUBLISH消息的交付质量级别。
具体的QoS级别如下表所示。
RETAIN
位置:
byte1,bit0
该标志位只用于PUBLISH消息。
当一个客户端发送一条PUBLISH消息给服务器,假设该消息所属的主题(topic)为topicA,如果该标志位被置位
(1),服务器在将该条消息发布给当前的所有topicA的订阅者之后,还应当保持这条消息。
当topicA出现了一个新的订阅者,则topicA的最后一条保持消息应当发给该订阅者。
当然,如果不存在保持消息,则什么也不用发。
当消息发布者以基于“reportbyexception”的方式发送消息时,这个功能就特别有用,因为这种情况下,消息发送间隔往往较长。
这个功能使得新的订阅者可以立刻收到之前保持的或上一个确定有效的消息。
当服务器收到某个主题的PUBLISH消息时,对于之前已经订阅该主题的客户端,服务器将给这些客户端发送这一PUBLISH消息,发送前,服务器会将该消息的RETAIN标志置为0(即不置位),不管服务器之前收到该PUBLISH消息时其RETAIN标志是否被置位。
这样做可以使得区分它接收到的PUBLISH消息是服务器之前保持的(RETAIN标志置位)还是即时收到的(RETAIN标志不置位)。
保持消息应当在重启服务器后仍能保留。
如果服务器收到有效载荷长度为0或重复主题的保持消息,服务器可以删除该保持消息。
剩余长度(RemainingLength)
位置:
byte2(从byte2,最大可至byte5)
该字段表示当前消息的剩余内容的字节数,包括可变头部和有效载荷的数据。
该字段本身的字节数是根据可变头部和有效载荷的长度不同而变化的。
该可变长度编码方案如下:
每个字节的低7位(7-0位)编码剩余长度的数据,第8位表示后面是否还有编码剩余长度的字节。
即每个字节编码128个值和一个“延续位”。
所以只用一个字节时,最大只可表示127字节的长度。
举例如下,十进制数字64只需用1个字节来编码,即0x40。
十进制数字321(=65+2x128)则需要用2个字节来编码,其中第1个字节为11000001,该字节的低7位表示65,第8位表示后面还有字节;第2个字节为00000010,表示2x128。
协议限制该字段最大为4个字节,这允许应用程序发送的最大消息长度为268435455(256MB),即0xFF,0xFF,0xFF,0x7F。
下表给出了增加该字段的字节数时相应可表示的剩余长度值。
该编码方案的算法如下所示,输入为一个十进制数(X),输出为编码后的结果。
do
digit=XMOD128
X=XDIV128
//iftherearemoredigitstoencode,setthetopbitofthisdigit
if(X>0)
digit=digitOR0x80
endif
'output'digit
while(X>0)
其中,MOD是模运算符(在C语言中相当于%),DIV表示整数除法(在C语言中相当于/),OR是位或运算符(在C语言中相当于|)。
相应地,剩余长度字段的解码算法如下所示:
multiplier=1
value=0
do
digit='nextdigitfromstream'
value+=(digitAND127)*multiplier
multiplier*=128
while((digitAND128)!
=0)
其中,AND是位与运算符(在C语言中相当于&)。
当该解码算法终止,value等于剩余长度的字节数。
值得注意的是,剩余长度编码不是可变头部的一部分。
剩余长度的值不包括用于编码剩余长度的字节数。
这部分“增加的长度”(1-3字节)是固定头部的一部分,而不属于可变头部。
译者注:
可认为剩余长度字段虽然是固定的,但该字段的长度却是变化的(1-4字节)。
2.2可变头部(Variableheader)
某些类型的MQTT命令消息还包含了一个可变头部,它位于固定头部和有效载荷之间。
可变的剩余长度字段(1-4字节)不是可变头部的一部分。
剩余长度字段的值不包括该字段本身的长度。
该值只包括可变头部和有效载荷。
更多细节可可见固定头部。
可变头部中各个字段的格式将在后续章节中进行详细介绍,介绍顺序与该字段在可变头部中的顺序一致。
协议名称(Protocolname)
协议名称字段只用于MQTTCONNECT消息的可变头部中。
该字段以UTF编码方式显示协议名称:
MQIsdp,大小写如上所示。
协议版本(Protocolversion)
协议版本字段只用于MQTTCONNECT消息的可变头部中。
该字段用8位无符号值来表示客户端所使用的协议修订级别。
当前版本协议中该字段的值为3(0x03),如下表所示。
连接标志(Connectflags)
该字段用于CONNECT消息的可变头部中,占1字节,包括Cleansession、Will、WillQoS和Retain标志。
Cleansession标志
位置:
bit1(在连接标志字节中,下同)
如果没有被置位(即值为0),则当客户端断线时,服务器必须保存该客户端的订阅信息,包括断线期间发布的该客户端订阅的主题中交付质量级别为QoS1和QoS2的消息,这样当客户端重连时,这部分消息能确保被送达到客户端。
同时,服务器还必须保持客户端在断线的那个时刻正在传输中的消息的状态,直到客户端重新连接。
如果被置位(即值为1),则服务器必须丢弃任何之前保持的该客户端的信息,将该连接视为“不存在(Clean)”。
同时,当客户端断线时,服务器必须丢弃其所有状态。
通常情况下,客户端会一直在其中一种模式下操作,不会进行切换。
该选择取决于具体应用的需求。
一个Cleansession客户端将不会收到过时的信息,且它每次重连时都需要重新订阅主题。
而一个non-cleansession客户端则不会漏接任何它在断线时服务器发布的交付质量级别为QoS1和QoS2的消息。
QoS0级别的消息由于只是尽可能的交付,所以它永远不会被存储保持。
这个标志以前被称为“Cleanstart”。
因为这个标志其实是作用于整个会话期间的,而不只是在连接的开始阶段,为了明确这个事实,所以将它重命名为“Cleansession”。
服务器可以提供一种管理机制,当确定一个客户端将永远不会重新连接时,可以清除该客户端的存储信息。
连接标志中的第0位在目前协议版本中没有使用到,保留为将来使用。
。
Will标志
位置:
bit2
Will消息是指当服务器与客户端通信过程中出现故障或客户端在保活时间内没有与服务器保持正常交流时,服务器特意发给客户端的消息。
当客户端通过发送DISCONNECT消息正常断开时,Will消息不会发送。
如果Will标志被置位,则WillQoS标志和WillRetain标志的设置将会发生作用,同时,在有效载荷里必须填写Will主题和Will消息内容字段。
Will标志的格式如下表所示。
连接标志中的第0位在目前协议版本中没有使用到,保留为将来使用。
WillQoS
位置:
bit4-3
WillQoS标志用来设置当客户端异常离线时,服务器发送的Will消息的交付质量级别。
Will消息的内容在客户端发送的CONNECT消息里的有效载荷里填写。
如果Will标志被置位,则WillQoS字段必须填写,否则该字段的值将被忽略。
WillQoS字段的可选值有0(0x00),1(0x01)和2(0x02),格式如下表所示。
连接标志中的第0位在目前协议版本中没有使用到,保留为将来使用。
WillRetain标志
位置:
bit5
WillRetain标志指明服务器是否需要保持客户端异常离线时发送给客户端的Will消息。
如果Will标志被置位,则WillRetain标志必须填写,否则其将被忽略。
该标志的格式如下表所示。
连接标志中的第0位在目前协议版本中没有使用到,保留为将来使用。
Usernameandpassword标志
位置:
bit6和bit7
客户端在连接服务器时可以指定用户名和密码,通过将用户名标志和密码标志(可选)置位表明在CONNECT消息的有效载荷里包含有用户名和密码。
如果将用户名标志置位,则必须在有效载荷里填写用户名字段,否则用户名字段将被忽略。
同样地,如果密码标志被置位,则必须在有效载荷里填写密码字段,否则密码字段将被忽略。
只提供密码而不提供用户名是不合法的。
连接标志中的第0位在目前协议版本中没有使用到,保留为将来使用。
保活计时器(KeepAlivetimer)
保活计时器用于MQTTCONNECT消息的可变头部中。
保活计时器定义了服务器收到客户端消息的最大时间间隔,它以秒为单位。
它使得服务器不需要等待漫长的TCP/IP超时就可以检测与客户端的网络连接是否断开。
客户端有义务在每个保活时间间隔内至少发送一条消息给服务器。
如果这期间没有业务相关的消息要发送,客户端则发送一个PINGREQ消息给服务器,相应地服务器返回一个PINGRESQ消息给客户端。
如果服务器在1.5个保活时间(可宽容0.5个保活时间)内都没有收到客户端的消息,则服务器将其视为客户端发送了一个DISCONNECT消息,并断开与客户端的连接。
这个动作不影响客户端的订阅。
具体细节参见 DISCONNECT。
如果客户端在发送PINGQ后的一个保活时间内没有收到服务器发来的PINGRESP消息,则客户端可以关闭TCP/IP套接字连接。
保活计时器用2个字节来表示,时间单位为秒。
实际设定的值由特定应用决定,不过通常它的值都设为数分钟,最大值接近18个小时。
如果设为0,则表示客户端不断线。
保活计时器的格式如下表所示。
2个字节的顺序为先MSB,再LSB(大端模式)。
连接返回码(Connectreturncode)
连接返回码用于CONNACK消息的可变头部中。
这个字段用一个无符号字节来表示返回码。
这些值的含义如下表所示。
值为0的返回码通常表示连接成功。
主题名(Topicname)
主题名用于PUBLISH消息的可变头部中。
主题名决定消息要发送到哪个信息通道。
订阅者使用主题名来决定他们要从哪些信息通道接收消息。
主题名是一个UTF编码字符串。
更多信息参见MQTT和UTF-8。
主题名支持的最大字符度为32767。
2.3有效载荷(Payload)
以下类型的MQTT命令消息拥有一个有效载荷:
CONNECT
该有效载荷包含了一个或多个UTF-8编码字符串。
它们包括标识客户端的唯一标识符、Will主题和消息、要使用的用户名和密码。
其中只有第一项是必选的,其余的取决于可变消息头部中的标志置位情况。
SUBSCRIBE
该有效载荷包含一系列要订阅的主题名,以及每个主题的QoS级别。
这些字符串都是UTF编码的。
SUBACK
该有效载荷包含一系列授权过的QoS级别。
它们是服务器管理员允许授权给客户端订阅的各个主题的QoS级别。
授权的QoS级别顺序与相应订阅的主题的顺序保持一致。
PUBLISH
该有效载荷只包含应用特定的数据。
协议不对数据的属性和内容作任何假设,协议把消息的这部分内容视为一个BLOB。
如果你想要对有效载荷数据进行压缩,你必须自己在有效载荷里定义合适的标志来处理压缩事宜。
你不能在固定状况或可变头部里定义与特定应用相关的标志。
2.4消息标识符(MessageIdentifiers)
消息标识符用于以下MQTT消息的可变头部中:
PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK。
消息标识符(消息ID)字段只存在于固定头部中QoS标志值为1或2的消息中。
更多信息可参见交付质量级别和消息流。
消息ID用16位无符号整数来表示,在同一个方向上的在传消息ID必须是唯一的。
它通常是逐个消息递增的,但不强制如此。
客户端与它所连接的服务器一样,都需要维护自己的消息ID列表,二者的消息ID列表互不影响。
客户端在发送一个消息ID为1的PUBLISH消息的同时也有可能收到来自服务器的消息ID为1的PUBLISH消息。
表示消息ID的2个字节的顺序为先MSB,再LSB(大端模式)。
不要使用值为0的消息ID。
它是作为无效消息ID保留的。
2.5MQTT和UTF-8(MQTTandUTF-8)
UTF-8是一种针对Unicode的可变长度字符编码,它优化了ASCII字符集的编码,以支持基于文本的通信。
在MQTT中,字符串编码的头2个字节用来记录字符串的长度,如下表所示。
字符串长度表示所有字符经过UTF-8编码后的字节数,而不是字符串中字符的个数。
例如,经过UTF-8编码后的字符串 OTWP 如下表所示。
Java中的 writeUTF() 和 readUTF() 数据流方法也使用这种格式。
2.6未使用的位(Unusedbits)
任何标明为未使用的位都应当置为0。
3.命令消息(Commandmessages)
3.1CONNECT-客户端请