一、介绍
MQTT使用的底层传输协议基础设施。
- 客户端使用它连接服务端。
- 它提供有序的、可靠的、双向字节流传输。
客户端:使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以
- 发布应用消息给其它相关的客户端。
- 订阅以请求接受相关的应用消息。
- 取消订阅以移除接受应用消息的请求。
- 从服务端断开连接。
服务端 :一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端
- 接受来自客户端的网络连接。
- 接受客户端发布的应用消息。
- 处理客户端的订阅和取消订阅请求。
- 转发应用消息给符合条件的已订阅客户端。
订阅 Subscription
订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅与单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。
主题名 Topic Name
附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。
主题过滤器 Topic Filter
订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。
会话 Session
客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端和服务端的多个连续网络连接间扩展。
控制报文 MQTT Control Packet
通过网络连接发送的信息数据包。MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。
二、MQTT控制报文的结构
MQTT协议通过交换预定义的MQTT控制报文来通信。包含固定报头、可变报头、有效载荷三部分:
image.png
2.1 固定报头
每个MQTT控制报文都包含一个固定报头。
image.png
其中,
-
控制报文的类型:
image.png -
指定控制报文类型的标志位:
image.png -
剩余长度:表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。剩余长度字段最大4个字节。
2.2 可变报头
可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
image.png
客户端和服务端彼此独立地分配报文标识符。因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换。
image.png2.3 有效载荷
某些MQTT控制报文在报文的最后部分包含一个有效载荷。
image.png
三、MQTT控制报文
3.1 CONNECT – 连接服务端
客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文。
有效载荷包含一个或多个编码的字段。包括客户端的唯一标识符,Will主题,Will消息,用户名和密码。除了客户端标识之外,其它的字段都是可选的,基于标志位来决定可变报头中是否需要包含这些字段。
-
固定报头
image.png -
可变报头
CONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。
image.png - 有效载荷
CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码
3.2 CONNACK – 确认连接请求
服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文必须是CONNACK.
-
固定报头
image.png -
可变报头
image.png -
有效载荷
CONNACK报文没有有效载荷。
PUBLISH – 发布消息
PUBLISH控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息。
-
固定报头
image.png
其中,服务质量定义如下:
image.png
-
可变报头
image.png -
有效载荷
有效载荷包含将被发布的应用消息。 -
响应
image.png
PUBACK –发布确认
PUBACK报文是对QoS 1等级的PUBLISH报文的响应。
-
固定报头
image.png -
可变报头
image.png -
有效载荷
PUBACK报文没有有效载荷。
PUBREC – 发布收到(QoS 2,第一步)
PUBREC报文是对QoS等级2的PUBLISH报文的响应。它是QoS 2等级协议交换的第二个报文。
-
固定报头
image.png -
可变报头
可变报头包含等待确认的PUBLISH报文的报文标识符。
image.png -
有效载荷
PUBREC报文没有有效载荷。
PUBREL – 发布释放(QoS 2,第二步)
PUBREL报文是对PUBREC报文的响应。它是QoS 2等级协议交换的第三个报文。
-
固定报头
image.png -
可变报头
可变报头包含与等待确认的PUBREC报文相同的报文标识符。
image.png -
有效载荷
PUBREL报文没有有效载荷。
PUBCOMP – 发布完成(QoS 2,第三步)
PUBCOMP报文是对PUBREL报文的响应。它是QoS 2等级协议交换的第四个也是最后一个报文。
-
固定报头
image.png -
可变报头
可变报头包含与等待确认的PUBREL报文相同的报文标识符。
image.png
SUBSCRIBE - 订阅主题
客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给与那些订阅匹配的主题,服务端发送PUBLISH报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据这个发送应用消息给客户端。
-
固定报头
image.png -
可变报头
image.png -
有效载荷
SUBSCRIBE报文的有效载荷包含了一个主题过滤器列表(至少一个),它们表示客户端想要订阅的主题。
有效载荷格式:
image.png
有效载荷例子:
image.png
SUBACK – 订阅确认
服务端发送SUBACK报文给客户端,用于确认它已收到并且正在处理SUBSCRIBE报文。
SUBACK报文包含一个返回码清单,它们指定了SUBSCRIBE请求的每个订阅被授予的最大QoS等级。
-
固定报头
image.png -
可变报头
image.png -
有效载荷
有效载荷包含一个返回码清单。每个返回码对应等待确认的SUBSCRIBE报文中的一个主题过滤器。返回码的顺序必须和SUBSCRIBE报文中主题过滤器的顺序相同
例子:
image.png
UNSUBSCRIBE –取消订阅
客户端发送UNSUBSCRIBE报文给服务端,用于取消订阅主题。
-
固定报头
image.png -
可变报头
image.png -
有效载荷
UNSUBSCRIBE报文的有效载荷包含客户端想要取消订阅的主题过滤器列表。UNSUBSCRIBE报文中的主题过滤器必须是连续打包的、按照1.5.3节定义的UTF-8编码字符串
image.png -
响应
UNSUBSCRIBE报文提供的主题过滤器(无论是否包含通配符)必须与服务端持有的这个客户端的当前主题过滤器集合逐个字符比较。如果有任何过滤器完全匹配,那么它(服务端)自己的订阅将被删除,否则不会有进一步的处理 。
如果服务端删除了一个订阅:
- 它必须停止分发任何新消息给这个客户端 。
- 它必须完成分发任何已经开始往客户端发送的QoS 1和QoS 2的消息。
- 它可以继续发送任何现存的准备分发给客户端的缓存消息。
服务端必须发送UNSUBACK报文响应客户端的UNSUBSCRIBE请求。UNSUBACK报文必须包含和UNSUBSCRIBE报文相同的报文标识符。即使没有删除任何主题订阅,服务端也必须发送一个UNSUBACK响应。
如果服务端收到包含多个主题过滤器的UNSUBSCRIBE报文,它必须如同收到了一系列的多个UNSUBSCRIBE报文一样处理那个报文,除了将它们的响应合并到一个单独的UNSUBACK报文外。
UNSUBACK – 取消订阅确认
服务端发送UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文。
-
固定报头
image.png -
可变报头
可变报头包含等待确认的UNSUBSCRIBE报文的报文标识符。
image.png -
有效载荷
UNSUBACK报文没有有效载荷。
PINGREQ – 心跳请求
客户端发送PINGREQ报文给服务端的。用于:
- 在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
- 请求服务端发送 响应确认它还活着。
- 使用网络以确认网络连接没有断开。
-
固定报头
image.png -
可变报头
PINGREQ报文没有可变报头。 -
有效载荷
PINGREQ报文没有有效载荷。 -
响应
服务端必须发送 PINGRESP报文响应客户端的PINGREQ报文
PINGRESP – 心跳响应
服务端发送PINGRESP报文响应客户端的PINGREQ报文。表示服务端还活着。
-
固定报头
image.png -
可变报头
PINGRESP报文没有可变报头。 -
有效载荷
PINGRESP报文没有有效载荷。
DISCONNECT –断开连接
DISCONNECT报文是客户端发给服务端的最后一个控制报文。表示客户端正常断开连接。
-
固定报头
image.png -
可变报头
DISCONNECT报文没有可变报头。 -
有效载荷
DISCONNECT报文没有有效载荷。 -
响应
客户端发送DISCONNECT报文之后:- 必须关闭网络连接。
- 不能通过那个网络连接再发送任何控制报文。
服务端在收到DISCONNECT报文时:
- 必须丢弃任何与当前连接关联的未发布的遗嘱消息。
- 应该关闭网络连接,如果客户端 还没有这么做。
四、操作行为
4.1 服务质量等级和协议流程 QoS
MQTT按照这里定义的服务质量 (QoS) 等级分发应用消息。分发协议是对称的,分发协议关注的是从单个发送者到单个接收者的应用消息。服务端分发应用消息给多个客户端时,每个客户端独立处理。分发给客户端的出站应用消息和入站应用消息的QoS等级可能是不同的。
- QoS 0:最多分发一次
消息的分发依赖于底层网络的能力。接收者不会发送响应,发送者也不会重试。消息可能送达一次也可能根本没送达。
对于QoS 0的分发协议,发送者:
- 必须发送QoS等于0,DUP等于0的PUBLISH报文 [MQTT-4.3.1-1]。
对于QoS 0的分发协议,接收者:
1.接受PUBLISH报文时同时接受消息的所有权。
- QoS 1: 至少分发一次
服务质量确保消息至少送达一次。QoS 1的PUBLISH报文的可变报头中包含一个报文标识符,需要PUBACK报文确认。
对于QoS 1的分发协议,发送者:
- 每次发送新的应用消息都必须分配一个未使用的报文标识符。
2.发送的PUBLISH报文必须包含报文标识符且QoS等于1,DUP等于0。 - 必须将这个PUBLISH报文看作是 未确认的 ,直到从接收者那收到对应的PUBACK报文
对于QoS 1的分发协议,接收者:
- 响应的PUBACK报文必须包含一个报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。
2.发送了PUBACK报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH报文当作一个新的消息,并忽略它的DUP标志的值。
- QoS 2: 仅分发一次
这是最高等级的服务质量,消息丢失和重复都是不可接受的。使用这个服务质量等级会有额外的开销。
QoS 2的消息可变报头中有报文标识符。QoS 2的PUBLISH报文的接收者使用一个两步确认过程来确认收到。
对于QoS 2的分发协议,发送者:
- 必须给要发送的新应用消息分配一个未使用的报文标识符。
- 发送的PUBLISH报文必须包含报文标识符且报文的QoS等于2,,DUP等于0。
- 必须将这个PUBLISH报文看作是 未确认的 ,直到从接收者那收到对应的PUBREC报文。
- 收到PUBREC报文后必须发送一个PUBREL报文。PUBREL报文必须包含与原始PUBLISH报文相同的报文标识符。
- 必须将这个PUBREL报文看作是 未确认的 ,直到从接收者那收到对应的PUBCOMP报文。
- 一旦发送了对应的PUBREL报文就不能重发这个PUBLISH报文。
对于QoS 2的分发协议,接收者:
- 响应的PUBREC报文必须包含报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。
- 在收到对应的PUBREL报文之前,接收者必须发送PUBREC报文确认任何后续的具有相同标识符的PUBLISH报文。 在这种情况下,它不能重复分发消息给任何后续的接收者。
- 响应PUBREL报文的PUBCOMP报文必须包含与PUBREL报文相同的标识符。
- 发送PUBCOMP报文之后,接收者必须将包含相同报文标识符的任何后续PUBLISH报文当作一个新的发布。
4.2 主题名和主题过滤器
- 主题通配符
- 主题层级分隔符 Topic level separator
斜杠(‘/’ U+002F)用于分割主题的每个层级,为主题名提供一个分层结构。当客户端订阅指定的主题过滤器包含两种通配符时,主题层级分隔符就很有用了。主题层级分隔符可以出现在主题过滤器或主题名字的任何位置。相邻的主题层次分隔符表示一个零长度的主题层级。 - 多层通配符 Multi-level wildcard
数字标志(‘#’ U+0023)是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。多层通配符必须位于它自己的层级或者跟在主题层级分隔符后面。不管哪种情况,它都必须是主题过滤器的最后一个字符。 - 单层通配符
加号 (‘+’ U+002B) 是只能用于单个主题层级匹配的通配符。
在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级。然而它必须占据过滤器的整个层级。可以在主题过滤器中的多个层级中使用它,也可以和多层通配符一起使用。
- 主题层级分隔符 Topic level separator
- 以$开头的主题
服务端不能将 开头的主题名用作其他目的。- $SYS/ 被广泛用作包含服务器特定信息或控制接口的主题的前缀。
- 应用不能使用 $ 字符开头的主题。
- 主题语义和用法
主题名和主题过滤器必须符合下列规则:
- 所有的主题名和主题过滤器必须至少包含一个字符。
- 主题名和主题过滤器是区分大小写的。
- 主题名和主题过滤器可以包含空格。
- 主题名或主题过滤器以前置或后置斜杠 “/” 区分。
- 只包含斜杠 “/” 的主题名或主题过滤器是合法的。
- 主题名和主题过滤器不能包含空字符 (Unicode U+0000)。
- 主题名和主题过滤器是UTF-8编码字符串,它们不能超过65535字节.
如果订阅的主题过滤器与消息的主题名匹配,应用消息会被发送给每一个匹配的客户端订阅。主题可能是管理员在服务端预先定义好的,也可能是服务端收到第一个订阅或使用那个主题名的应用消息时动态添加的。服务端也可以使用一个安全组件有选择地授权客户端使用某个主题资源。
网友评论