MQTT协议原理
MQTT 3(当前版本3.1.1)是目前使用的最为广泛的MQTT协议标准。尽管MQTT5标准已经发布,并且带来了一些令人振奋的新特性,但是在整个应用场景上,从后台服务到消息中间件再到客户端SDK等环节上的产品升级并没有都完成,再加上既有部署的维护,业界从版本3到5的过渡可能会持续相当长一段时间。
在一个MQTT协议中有三个角色会参与到整个通信过程,发布者(publisher)、代理(broker)和订阅者(subscriber)。有别于传统的客户端/服务器通讯协议,MQTT协议并不是端到端的,消息传递通过代理,包括会话(session)也不是建立在发布者和订阅者之间,而是建立在端和代理之间。代理解除了发布者和订阅者之间的耦合。除了发布者和订阅者之间传递普通消息,代理还可以为发布者处理保留消息和遗愿消息,并可以更改服务质量(QoS)等级。
MQTT控制报文
MQTT协议工作在TCP之上,端和代理之间通过交换预先定义的控制报文来完成通信。MQTT报文有3个部分组成,并按下表顺序出现:
固定报头(fixed header) |
可变报头(variable header) |
荷载(payload) |
所有报文都包含 |
部分报文包含 |
部分报文包含 |
- 固定头(Fixed header):存在于所有的MQTT数据包中,用于表示数据包类型及对应标志、数据包大小等;
- 可变头(Variable header):存在于部分类型的MQTT数据包中,具体内容是由相应类型的数据包决定的;
- 消息体(Payload):存在于部分的MQTT数据包中,存储消息的具体数据。
固定头
固定头的第一个字节的高4位Bit用于表示该数据包的类型。MQTT的数据包有以下一些类型:
名称值方向描述Reserved0不可用保留位CONNECT1Client到BrokerClient请求连接到BrokerCONNACK2Broker到Client连接确认PUBLISH3双向发布消息PUBACK4双向发布确认PUBREC5双向发布收到PUBREL6双向发布释放PUBCOMP7双向发布完成SUBSCRIBE8Client到BrokerClient请求订阅SUBACK9Broker到Client订阅确认UNSUBSCRIBE10Client到BrokerClient请求取消订阅UNSUBACK11Broker到Client取消订阅确认PINGREQ12Client到BrokerPING请求PINGRESP13Broker到ClientPING应答DISCONNECT14Client到BrokerClient主动中断连接Reserved15不可用保留位
低4位Bit则用于表示数据包的Flag,不同的数据包类型,Flag的定义不同,每种数据包对应的Flag如下:
数据包标识位Bit 3Bit 2Bit 1Bit 0CONNECT保留位0000CONNACK保留位0000PUBLISHMQTT 3.1.1使用DUPQoSQoSRETAINPUBACK保留位0000PUBREC保留位0000PUBREL保留位0000PUBCOMP保留位0000SUBSCRIBE保留位0000SUBACK保留位0000UNSUBSCRIBE保留位0000UNSUBACK保留位0000PINGREQ保留位0000PINGRESP保留位0000DISCONNECT保留位0000
从固定头的第2字节开始是用于表示MQTT数据包剩余长度的字段,最少一个字节,最大四个字节。每一个字节的低7位用于标识值,范围为0~127。最高的1位是标识位,用来说明是否有后续字节来标识长度。标识为0,代表没有后续字节;标识为1,代表后续还有一个字节用于标识包的长度。MQTT协议相应字节数对应的最小、最大包长度如下表所示:
字节数最小包长度(除固定头外)最大包长度(除固定头外)10字节(0x00)127字节(0x7F)2128字节(0x80,0x01)16 383字节(0xFF,0x7F)316 384字节(0x80,0x80,0x01)2 097 151字节(0xFF,0xFF,0x7F)42 097 152字节(0x80,0x80,0x80,0x01)268 435 455字节(0xFF,0xFF,0xFF,0x7F)。可知MQTT协议中数据包(除固定头外)的最大长度为268435455字节,约256M。
报文种类
1.连接请求(CONNECT):当一个从客户端到服务器的TCP/IP套接字连接被建立时,必须用一个连接流来创建一个协议级别的会话。
2.连接请求确认(CONNECTACK):连接请求确认报文(CONNECTACK)是服务器发给客户端,用以确认客户端的连接请求
3.发布报文(PUBLISH):客户端发布报文到服务器端,用来提供给有着不同需求的订阅者们。每个发布的报文都有一个主题,这是一个分层的命名空间,他定义了报文来源分类,方便订阅者订阅他们需要的主题。订阅者们可以注册自己的需要的报文类别。
4.发布确认报文(PUBACK):发布确认报文(PUBACK)是对服务质量级别为1的发布报文的应答。他可以是服务器对发布报文的客户端的报文确认,也可以是报文订阅者对发布报文的服务器的应答。
5.发布确认报文(PUBREC):PUBREC报文是对服务质量级别为2的发布报文的应答。这是服务质量级别为2的协议流的第二个报文。PUBREC是由服务器端对发布报文的客户端的应答,或者是报文订阅者对发布报文的服务器的应答。
6.发布确认报文(PUBREL):PUBREL是报文发布者对来自服务器的PUBREC报文的确认,或者是服务器对来自报文订阅者的PUBREC报文的确认。它是服务质量级别为2的协议流的第三个报文。
7.确定发布完成(PUBCOMP):PUBCOMP报文是服务器对报文发布者的PUBREL报文的应答,或者是报文订阅者对服务器的PUBREL报文的应答。它是服务质量级别为2的协议流的第四个也是最后一个报文。
8.订阅命名的主题(SUBSCRIBE):订阅报文(SUBSCRIBE)允许一个客户端在服务器上注册一个或多个感兴趣的主题名字。发布给这些主题的报文作为发布报文从服务器端交付给客户端。订阅报文也描述了订阅者想要收到的发布报文的服务质量等级。
9.订阅报文确认(SUBACK):当服务器收到客户端发来的订阅报文时,将发送订阅报文的确认报文给客户端。一个这样的确认报文包含一列被授予的服务质量等级。被授予的服务质量等级次序和对应的订阅报文中的主题名称的次序相符。
10.退订命名的主题(UNSUBSCRIBE):退订主题的报文是从客户端发往服务器端,用以退订命名的主题。
11.退订确认(UNSUBACK):退订确认报文是从服务器发往客户端,用以确认客户端发来的退订请求报文。
12.Ping请求(PINGREQ)
Ping请求报文是从连接的客户端发往服务器端,用来询问服务器端是否还存在。
13.Ping应答(PINGRESP):Ping应答报文是从服务器端发往Ping请求的客户端,对客户端的Ping请求进行确认。
14.断开通知(DISCONNECT):断开通知报文是从客户端发往服务器端用来指明将要关闭它的TCP/IP连接,他允许彻底地断开,而非只是下线。如果客户端已经和干净会话标志集联系,那么所有先前关于客户端维护的信息将被丢弃。一个服务器在收到断开报文之后,不能依赖客户端关闭TCP/IP连接。
可变头
可变报文头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等,后面会针对此部分进行具体讲解。
消息体
当MQTT发送的消息类型是CONNECT(连接)、PUBLISH(发布)、SUBSCRIBE(订阅)、SUBACK(订阅确认)、UNSUBSCRIBE(取消订阅)时,则会带有负荷。