MQTT协议简析

1 概述

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一个C/S架构的发布/订阅模式消息传输协议,最早在1999年由IBM的Andy Stanford-Clark博士和Arcom公司的ArlenNipper博士提出,本文的MQTT协议主要基于MQTT3.1.1

2 报文结构

MQTT报文结构主要分为固定报头、可变报头、有效载荷3个部分,具体结构如下表所示:

说明 字节数 7 6 5 4 3 2 1 0
固定报头 1 Message Type Dup Flag QoS Level Retain Flag
  1~4 剩余长度,最小1字节最大4字节
可变报头 1 消息标识符最高有效位MSB
  1 消息标识符最低有效位LSB
有效载荷 N Payload

2.1 固定报头(Fixed Header)

每个MQTT报文都包含至少2个字节的固定报头,包括消息类型(Message Type)、重发标识(Dup Flag)、质量等级(QoS)、保持标识(Retain Flag)、剩余长度等字段。

2.1.1 消息类型

MQTT第1个字节的前4位表示消息类型,具体的消息类型定义如下表所示:

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

2.1.2 标识符

固定报头第一个字节的后4位为标识符,对于PUBLISH类型的消息来说,分别表示DUP、QoS、RETAIN3个标识,对于其他类型的消息来说,这4位为保留位,具体的值应该符合下表的定义,如果收到非法的标识符,协议的双方应该选择关闭网络连接。

控制报文 固定报头标志 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PUBLISH Used in MQTT 3.1.1 DUP1 QoS2 QoS2 RETAIN3
PUBACK Reserved 0 0 0 0
PUBREC Reserved 0 0 0 0
PUBREL Reserved 0 0 1 0
PUBCOMP Reserved 0 0 0 0
SUBSCRIBE Reserved 0 0 1 0
SUBACK Reserved 0 0 0 0
UNSUBSCRIBE Reserved 0 0 1 0
UNSUBACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0
2.1.2-1 重发标识(Dup Flag)

对PUBLISH类型的消息来说,MQTT第1个字节的第3位表示重发标识,主要用于保证消息可靠传输,默认值为0,表示第一次发送。

当QoS为大于0时,发布的消息需要回复确认,如果客户端或服务器端没有收到确认回复则尝试重发消息,此时消息的Dup Flag被置为1(需要指出的是,该标识位不能用于检测消息的重复发送)。

2.1.2-2 质量等级(QoS Level)

MQTT使用第1个字节第2、1位表示质量等级,具体的定义如下表所示:

QoS Level 2 1 说明
0 0 0 至多1次(At Most Once)
1 0 1 至少1次(At Least Once)
2 1 0 至多1次(Exactly Once)
3 1 1 保留值
2.1.2-3 保持标识(Retain Flag)

MQTT报文第1字节第0位用于保持标识,服务端和客户端处理保持标识时需要满足以下规则:

i.在客户端发给服务端的PUBLISH报文中,如果RETAIN标识被设置为1,服务端必须保存改消息及其QoS,以使该报文可以被投递给订阅了对应主题的新订阅者;

ii.当新的订阅建立时,服务端必须把每一个主题保持的最近一条RETAIN消息(如果存在的话),投递给订阅者;

iii.如果服务端收到QoS为0,RETAIN标识为1的消息,服务端必须丢弃该主题下保存的所有RETAIN消息,同时保存这条QoS为0的消息,但是这条消息可以随时被丢弃;

iv.当一个新订阅建立时,服务端发给客户端的PUBLISH报文需设置RETAIN为1,其他情况服务端发给客户端的PUBLISH报文的RETAIN位都需要被置为0,不管服务端收到该PUBLISH报文时它的标识是什么;

v.当一个0字节内容的PUBLISH报文的RETAIN标识为1时,服务端会把这条消息投递给订阅了对应主题的订阅者,同时清空这个主题下保持的所有消息。需要指出的是,客户端收到的这条消息的RETAIN标识为0,服务端不会保存0字节内容的消息;

vi.当客户端向服务端发布一条RETAIN为0的PUBLISH报文时,服务端不会保存这条消息,也不会删除或者替换已经保存的RETAIN为1的消息;

2.1.3 剩余长度

MQTT报文的剩余长度是指可变报头和有效载荷的字节总数,从第2个字节开始,最大包括4个字节,剩余长度字段的大小及其能表示的范围如下表所示:

字节数 最小值 最大值
1 0 (0x00) 127 (0x7F)
2 128 (0x80, 0x01) 16 383 (0xFF, 0x7F)
3 16 384 (0x80, 0x80, 0x01) 2 097 151 (0xFF, 0xFF, 0x7F)
4 2 097 152 (0x80, 0x80, 0x80, 0x01) 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)

剩余长度的编码算法伪代码如下:

do
    encodedByte = X MOD 128
    X = X DIV 128
    // if there are more data to encode, set the top bit of this byte
    if ( X > 0 )
        encodedByte = encodedByte OR 128
    endif
    ‘output‘ encodedByte
while ( X > 0 )

  

剩余长度的解码算法伪代码如下:

multiplier = 1
value = 0
do
    encodedByte = ‘next byte from stream‘
    value += (encodedByte AND 127) * multiplier
    multiplier *= 128
    if (multiplier > 128*128*128)
        throw Error(Malformed Remaining Length)
while ((encodedByte AND 128) != 0)

2.2 可变报头(Variable Header)

在某些类型的MQTT报文中存在位于固定报头和有效载荷之间的包含2个字节的可变报头。具体的报文类型包括PUBLISH (QoS > 0), PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK等。

2.2.1

可变报头需要满足以下规则:

2.2.1-1

SUBSCRIBE, UNSUBSCRIBE, PUBLISH (QoS > 0)等类型的报文必须包含一个16bit的报文标识符;

2.2.1-2

每次客户端发送上面几种类型的报文时,必须指定一个未使用过的标识符;

2.2.1-3

当一个客户端重发一个特定的MQTT报文时,重发的报文必须使用与被重发报文相同的报文标识符;

当客户端重发的报文被确认后,这个报文的标识符可以在下次重用;

重发报文被确认是指: QoS1的PUBLISH收到PUBACK, QoS2的PUBLISH收到PUBCOMP, SUBSCRIBE收到SUBACK, UNSUBSCRIBE收到UNSUBACK;

2.2.1-4

服务端发送QoS>0的PUBLISH消息也要遵循2.2.3相同的规则;

2.2.1-5

QoS为0的PUBLISH消息不能包含报文标识符字段;

2.2.1-6

PUBACK、PUBREC、PUBREL报文必须包含与相应的PUBLISH报文相同的报文标识符;

2.2.1-7

类似的,SUBACK和UNSUBACK消息必须包含与之对应的SUBSCRIBE和UNSUBSCRIBE报文相同的报文标识符;

2.2.2 包含报文标识符的报文

需要包含报文标识符的报文如下表所示:

控制报文 报文标识符字段
CONNECT 不需要
CONNACK 不需要
PUBLISH QoS > 0需要
PUBACK 需要
PUBREC 需要
PUBREL 需要
PUBCOMP 需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要

2.3 有效载荷Payload

有效载荷Payload即报文的正文部分,包含Payload字段的报文类型主要如下表所示:

控制报文 有效载荷
CONNECT 需要
CONNACK 不需要
PUBLISH 可选
PUBACK 不需要
PUBREC 不需要
PUBREL 不需要
PUBCOMP 不需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 不需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要

时间: 2024-10-08 20:38:59

MQTT协议简析的相关文章

TCP,UDP,IP 协议简析

现在的操作系统基本都实现了TCP/IP协议,TCP/IP协议栈分为五层: 应用层:向用户提供的一组常用的应用程序,如TELNET,FTP,SMTP,SNTP,DNS,HTTP,这些应用程序有一个端口用来标识. 传输层:主要协议是TCP和UDP,提供应用程序的通信. 网络层:主要协议是IP协议,定义了IP地址格式,是不同应用程序的数据在网络上通畅传输的关键. 链路层:这是TCP/IP软件的最低层,负责接收IP数据包并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层. 物理层: 每

STUN协议简析

http://blog.csdn.net/mazidao2008/article/details/4934257 ———————————————————————————————————————————————————— STUN简介 STUN(Simple Traversal of UDP over NATs,NAT 的UDP简单穿越)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端

HTTP协议--简析

HTTP--超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是所有的www文件都必须遵守的标准. 要想成为优秀的web开发人员,必须熟悉HTTP协议,今天,来给大家分享一下关于HTTP协议的认识.欢迎大家交流指正. HTTP协议是一个基于TCP协议,属于应用层的,面向对象的,无状态的,无连接的协议. 其简单快捷,客户向服务器请求服务时,只需要传送请求方法和路径.请求的方法有 POST.GET.HEAD.PUT等. 注意: 所谓无状态的

TCP 协议简析

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的.可靠的.基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接.它是个超级麻烦的协议,是互联网的基础,也是每个程序员必备的基本功.首先来看看OSI的七层模型: 我们需要知道TCP工作在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层:在第二层上的数据,我们把它叫Frame,在第三层上的数据叫Packet,

DNS使用的是TCP协议还是UDP协议简析

DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类.但很少有人知道DNS分别在什么情况下使用这两种协议. 先简单介绍下TCP与UDP.     TCP是一种面向连接的协议,提供可靠的数据传输,一般服务质量要求比较高的情况,使用这个协议.UDP---用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务. TCP与UDP的区别: UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同.TCP协议中

服务器租用---常用网络协议:TCP和UDP的区别简析

服务器租用---常用网络协议:TCP和UDP的区别简析及TCP与UDP区别 TCP---传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立 一个TCP连接,之后才能传输数据.TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一 端传到另一端. UDP---用户数据报协议,是一个简单的面向数据报的运输层协议.UDP不提供可靠性,它只是把应用程序传给IP层的 数据报发送出去,但是并不能保证它们能到达目的地.由于UDP在传输数据报

网络协议:简析三次握手协议

一,简析三次握手协议 首先来看我们生活中很常见的一件事: 在我们网购的时候,常常会跟客服这样聊天:我们向客服询问某件事,客服回答,然后我们断网了...过了一会儿,我们再登陆就收到了客服的回答. 这个交互的过程进行了三次才完成了一次应答,这个过程就类似我们采用TCP/IP协议访问服务器时的三次握手机制: 第一次握手: 建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认.SYN为同步序列编号. 第二次握手: 服务器收到SYN包,必须确认客户的SYN(ac

web应用构架LAMT及tomcat负载简析

Httpd    (mod_jk.so) workers.properties文件 uriworkermap.properties文件 <--AJP1.3--> Tomcat  --> jdk 大致流程:apache服务器通过mod_jk.so 模块处理jsp文件的动态请求.通过tomcat worker等待执行servlet/JSP的tomcat实例.使用 AJP1.3协议与tomcat通信.tomcat有借助jdk解析. 负载就是 多台tomcat.共同解析apache发送的jsp请

CentOS的网络配置简析

我们在进行对CentOS的网络配置时,一般会从IP地址(IPADDR).子网掩码(NETMASK).网关(Gateway).主机名(HOSTNAME).DNS服务器等方面入手.而在CentOS中,又有着不同的命令或配置文件可以完成这些配置操作,接下来,我们将从ifcfg系命令,iproute2系命令以及配置文件3个方面来简析网络配置的方法. 一.ifcfg系命令 ifcfg系命令包括ifconfig,route,netstat和hostname. 1.ifconfig命令 用来配置一个网络接口.