MQTT是一款基于发布订阅模式的轻量级通讯协议,构建于TCP/IP协议之上。应用在有限带宽、低开销和不可靠网络的环境中。
在物联网场景下,MQTT成为连接设备、传递实时数据以及实现设备间协同操作的关键工具。通过发布/订阅模式,设备可以异步地共享信息,网关与服务器之间可以灵活地传递数据,而且MQTT的轻量级设计使得它成为移动设备和传感器等资源有限设备的理想选择。
无论是追踪物流中的货物、监测环境中的传感器数据,还是控制智能家居中的设备,MQTT都以其高效、灵活的特性融入到各种场景中,成为连接物理世界和数字世界的重要纽带。在这个快速发展的数字化时代,MQTT的重要性愈发显著,为我们构建更智能、更互联的未来奠定了坚实的基础。
既然MQTT是一个消息协议,那它就会有自己的消息规则,即规定这条消息该以怎样的格式进行传输。
MQTT消息的数据包结构分为固定头、可变头和有效载荷。
固定头的大小至少为两个字节,第一个字节高4位bit代表消息类型,低四位代表消息类型的具体标识,如DUP重发标识、Qos等级、保留标识等信息,有的消息类型没有;第二个字节标识了可变头和有效载荷的长度。固定头的消息类型代表数据包的类型,比如CONNECT、PUBLISH、SUBSCRIBE等,DUP用来标识是否为重发的消息,Qos定义了消息的服务质量,保留标识位标识服务器是否保留此消息。
MQTT定义了多种消息类型,每种类型用于不同的通信场景。以下是MQTT的主要消息类型:
标志位包括控制消息流的标志,以及质量服务等级(QoS)标志。
长度可变,根据固定头中的剩余长度字段确定,不同消息类型的可变头内容各不相同。下面列举几种消息类型的可变头:
对于CONNECT消息,可变头包含协议名、协议级别、连接标志、保持连接。
标识了使用的协议,对于MQTT来说,它是"MQTT",用于确保客户端和服务器都使用相同的协议进行通信。
指定了MQTT协议的版本,对于MQTT 3.1.1版本,协议级别的值是4,这有助于确保客户端和服务器使用相同版本的协议进行通信。
包含了一系列标志位,用于控制连接的各个方面。
CONNECT消息的连接标志包括:
当使用MQTT协议时,保持连接(Keep Alive)是连接标志的一个重要方面。在CONNECT消息的连接标志中,有一个字段叫做Keep Alive,它表示客户端和服务器之间的保持连接时间间隔。
通过Keep Alive机制,MQTT可以在不断开连接的情况下保持通信链路的有效性。这对于在不稳定的网络环境中保持可靠的通信非常重要,因为它允许及时检测到连接故障并采取相应的措施。
对于PUBLISH消息,可变头包含主题名、报文标识符(如果QoS级别大于0)、保留标志等。
表示消息发布的主题,主题是消息的关键标识符,订阅者可以使用主题来过滤感兴趣的消息。
仅在消息的质量服务等级(QoS)大于0时存在,用于确保消息的可靠传递。当QoS级别为1时,PUBLISH消息需要收到对应的PUBACK消息,而在QoS级别为2时,需要收到PUBREC和PUBCOMP两个消息,报文标识符在客户端和服务器之间保证消息传递的有序性和完整性。
指定了消息在服务器上的保留策略,如果保留标志被设置为1,表示服务器应该保留最后一条与该主题相关的消息,以便新订阅者在订阅该主题时能够收到最新的保留消息。保留消息是一种特殊的消息,它会一直存储在服务器上,直到被替代为止。
对于SUBSCRIBE消息,可变头主要包含报文标识符
与PUBLISH消息一样,用于确保消息的可靠传递。在订阅后,服务器会使用这个标识符来标识和关联订阅确认消息(SUBACK)(将SUBSCRIBE消息与SUBACK(订阅确认)进行匹配)。
包含实际的消息内容。下面列举几种消息类型的有效载荷:
每个连接到MQTT服务器的客户端都必须有一个唯一的客户端标识符。客户端标识符用于在服务器端标识和管理连接。它是CONNECT消息的有效载荷中的一个必需字段。
如果CONNECT消息的Will Flag被设置为1,表示客户端希望发送"遗嘱消息",则需要提供Will Topic。
Will Topic是遗嘱消息将要发布的主题。
如果CONNECT消息的Will Flag被设置为1,表示客户端希望发送"遗嘱消息",则需要提供Will Message。
Will Message是遗嘱消息的实际内容。
如果CONNECT消息的User Name Flag被设置为1,表示CONNECT消息包含用户名,则需要提供用户名。
如果CONNECT消息的Password Flag被设置为1,表示CONNECT消息包含密码,则需要提供密码。
PUBLISH的有效负荷包含要发布的信息,并且该消息的接收者必须按照PUBLISH固定头的Qos等级发送响应
包含订阅和取消订阅的主题和Qos等级。
MQTT采用发布/订阅模式(Publish/Subscribe),这是一种消息传递模型,其中消息的生产者称为发布者(Publisher),而消息的消费者称为订阅者(Subscriber)。
例如在一个物联网场景下,物联网设备网关内部会有一个MQTT Client(数据包转发器,采用MQTT协议),这时网络服务器(相应的物联网协议对应的网络服务器)充当一个MQTT Broker,网关接收到感应器数据后,将数据加密后发布到相应的MQTT Topic(会与Device EUI相关联)上,我们的应用服务器便可在网络服务器的MQTT Broker上根据Topic(注意这里的Topic与网关下发到网络服务器的Topic不一样,由于网关的数据是加密的,这Topic上是处理过后的数据)订阅(可通过通配符同时订阅多个感应器数据)需要的感应器数据。
发布者是消息的生产者,负责产生和发布消息。发布者将消息发送到特定的主题(Topic),主题是消息的标识符,用于描述消息的内容或用途。
订阅者是消息的消费者,负责接收和处理消息。订阅者通过订阅特定的主题表达对消息的兴趣,只有订阅了某个主题的订阅者才会收到与该主题相关的消息。
主题是消息的逻辑通道,用于将消息分类或标识。发布者发布消息时将其发送到特定的主题,而订阅者则通过订阅特定主题来表达对消息的兴趣。主题的层次结构允许灵活的消息过滤和定制化订阅。
订阅者通过向MQTT服务器发送订阅请求,表达对特定主题的兴趣。订阅后,订阅者将开始接收与其订阅主题相关的消息。
发布者通过向MQTT服务器发送发布请求,将消息发布到特定主题。发布消息后,所有订阅了相同主题的订阅者都会收到该消息。
发布者可以设置遗嘱消息,即在发布者异常断开连接时,服务器会向预定的主题发送预定义的消息。遗嘱消息是在建立连接时设置的,用于处理连接中断的情况。
Qos是消息服务质量等级,用于保障消息的传达。
Qos分为:
最多一次,发送者只发送一次PUBLISH报文给接收者,无论接收者是否真的收到,依赖于底层TCP的重传;
至少一次,发送端向接收端发送一个带有数据的PUBLISH包,并在本地保存这个包,接收端收到这个包后,会发送一条确认报文PUBACK给发送端,PUBACK数据包没有消息体(Payload),在可变头中有一个包标识(Packet Identifier),和它收到的PUBLISH包中的Packet Identifier一致。如果发送端收到了这条PUBACK确认报文,根据PUBACK包中的Packet Identifier找到本地保存的PUBLISH包,然后丢弃掉,一次消息的发送完成。如果发送端没有收到PUBACK报文,那么它将PUBLISH包的DUP标识设为1(代表是重新发送的PUBLISH包),重新发送该PUBLISH包。接收端可能会收到重复的消息。
正好一次,发送端发送Qos为2的PUBLISH数据包给接收端,并且在本地保存一份,接收端回复PUBACK确认报文,并在本地也保存一份 PUBLISH 包,当Sender收到PUBREC,它就可以安全的丢弃掉初始Packet Identifier的PUBLISH数据包,同时保存该PUBREC包,并且返回PUBREL报文作为应答,当接收端收到PUBREL报文后,会应答发送端一条PUBCOMP报文,Sender收到PUBCOMP包,那么认为传输已完成,则丢掉对应的PUBREC数据包。至此,一次QoS2的MQTT消息传输就结束了。
Receiver可能会收到多个重复的PUBLISH包,更加完善的处理如下:
Receiver在收到PUBLISH数据包之后,马上回复一个PUBREC数据包。并会在本地保存PUBLISH包的Packet Identifier,不管之后因为重传多少次这个Packet Identifier的数据包,Receiver都认为是重复的,丢弃。Receiver接收到QoS为2的PUBLISH数据包后,并不马上投递给上层,而是在本地做持久化,将消息保存起来(这里需要是持久化而不是保存在内存)。Receiver收到PUBREL数据包后,正式将消息递交给上层应用层,投递之后销毁Packet Identifier,并发送PUBCOMP数据包,销毁之前的持久化消息。之后不管接收到多少个PUBREL数据包,因为没有Packet Identifier,直接回复PUBCOMP数据包即可