目录
一.MQTT协议概述
1.1简述
MQTT(Message Queuing Telemetry Transport)是一种轻量级的通信协议,专门设计用于在低带宽、不稳定网络环境中进行高效的通信。它最初由IBM开发,后来成为开放标准,广泛应用于物联网(IoT)和传感器网络中。
MQTT协议的主要特点包括:
-
轻量级: MQTT协议设计简单,消息头部较小,适用于资源有限的设备和低带宽网络。
-
发布/订阅模式: MQTT采用发布/订阅(Publish/Subscribe)模式,其中设备可以发布(发送)消息到主题(Topic),其他设备可以订阅(接收)这些主题上的消息。
-
主题层级结构: 主题是消息的逻辑标识符,可以看作是消息的目的地。主题可以使用层级结构进行组织,例如:“sensors/temperature”表示温度传感器的温度值。
-
QoS等级: MQTT支持不同的服务质量(Quality of Service,QoS)等级,用于确保消息的可靠传递。QoS级别包括0、1和2,分别表示最多一次、最少一次和正好一次的传递保证。
-
保留消息: 设备可以发布一个保留消息到主题,以便新订阅者能够立即获得最新状态的信息。
-
遗嘱消息: 客户端可以设置一个遗嘱消息,在客户端异常断开连接时,服务器会自动发送这个遗嘱消息给指定的主题,用于通知其他设备。
-
Session保持: MQTT允许客户端保持会话状态,这意味着即使网络连接中断,客户端可以在恢复连接后继续订阅之前的主题。
MQTT协议在物联网和传感器网络领域得到了广泛的应用,因为它能够有效地在各种网络条件下传递数据,同时减少了网络和设备资源的负担。它被用于从温度传感器到工业自动化系统等各种场景中。
1.2 名词解释
1.2.1客户端(Client)
在MQTT中,客户端是指使用MQTT协议与MQTT代理(也称为MQTT服务器或MQTT broker)进行通信的各个实体。客户端可以是发布者、订阅者或同时兼具两者功能的实体
MQTT客户端的两个主要角色是发布者(Publisher)和订阅者(Subscriber):
-
发布者(Publisher): MQTT发布者是发送消息到特定主题的设备或应用程序。发布者将消息发布到特定主题后,所有订阅了这个主题的订阅者都可以接收到该消息。发布者负责将信息传递给MQTT代理,然后代理将消息传递给订阅者。
-
订阅者(Subscriber): MQTT订阅者订阅特定主题,以接收该主题上发布的消息。一旦有新消息发布到已订阅的主题,订阅者将会收到这些消息。订阅者可以在消息到达时执行相应的操作,如处理数据、更新状态等。
MQTT客户端可以通过各种编程语言和库来实现,以便与MQTT代理进行通信。在你提供的示例中,Python中的paho.mqtt.client
模块被用来创建MQTT客户端。这个模块提供了许多功能,包括连接到代理、发布消息、订阅主题、处理接收到的消息等。
MQTT客户端是指使用MQTT协议进行通信的各种实体,包括发布者和订阅者,它们通过主题进行消息传递,从而实现设备间的高效通信。
1.2.2服务端(Server)
MQTT的服务端,也称为MQTT代理(MQTT broker)或MQTT服务器,是负责管理和协调MQTT客户端之间通信的中心组件。它是实现MQTT协议的核心部分,负责接收、处理和转发消息,以及维护客户端的连接状态、订阅关系和QoS级别等。
MQTT代理的主要功能包括:
-
客户端连接管理: MQTT代理管理客户端的连接和断开,维护客户端的会话状态,确保客户端可以可靠地连接和重新连接。
-
消息传递: 代理接收来自发布者的消息,并将其传递给相应订阅者。它负责在不同的主题间转发消息,同时根据订阅关系和QoS级别确保消息的可靠传递。
-
主题订阅与分发: 代理管理客户端的主题订阅关系,当有新消息发布到某个主题时,它会将消息传递给订阅了该主题的所有客户端。
-
QoS级别的管理: 代理根据QoS级别,确保消息的适当传递。在QoS级别1和2下,代理需要进行消息的确认和重传,以保证消息可靠性。
-
安全性与身份验证: MQTT代理提供安全性功能,支持身份验证和加密通信,以保护数据的隐私和完整性。
-
持久化: 代理通常支持将消息持久化,以防止消息丢失,特别是在断开连接后。
-
负载均衡: 对于大规模的MQTT网络,可以使用多个MQTT代理来实现负载均衡,以分散客户端连接和消息传递的负载。
-
协议支持: MQTT代理通常支持多个MQTT协议版本,以适应不同版本的客户端。
在物联网应用中,MQTT代理起着至关重要的作用,它为设备间的通信提供了可靠的中间件层。使用MQTT代理,可以有效地实现设备之间的高效通信,同时根据不同的需求选择合适的QoS级别,平衡通信的可靠性和开销。
1.2.3主题(Topic)
MQTT的主题(Topic)是在MQTT协议中用于消息发布和订阅的一种机制。主题可以看作是消息的目的地,它是一个用于标识消息类型或内容的字符串。当客户端发布消息时,可以将消息发布到一个特定的主题上;而订阅者则可以选择订阅一个或多个主题,以接收与这些主题相关的消息。
主题在MQTT中有以下特点:
-
层级结构: 主题可以是层级结构的,由多个层级组成,层级之间用斜杠(/)分隔。例如,"home/living-room/temperature"就是一个具有三个层级的主题,表示测量客厅温度的消息。
-
通配符支持: MQTT支持通配符用于订阅多个相关主题。有两种通配符:"+"(加号)用于匹配单个层级,"#"(井号)用于匹配一个或多个层级。例如,"home/+/temperature"可以匹配"home/living-room/temperature"和"home/kitchen/temperature"等主题。
-
发布/订阅模式: 发布者将消息发布到一个特定的主题上,而订阅者可以订阅一个或多个主题,以接收感兴趣的消息。当有新消息发布到订阅的主题时,订阅者会收到相应的消息。
-
灵活性: 主题的灵活性使得在物联网应用中可以轻松地组织和管理消息。设备可以根据自身的功能、位置、状态等选择合适的主题,从而实现高效的消息传递。
-
语义信息: 主题可以包含有关消息内容的语义信息,使得订阅者可以根据主题了解消息的类型或用途。
例如,假设有一个温度传感器发布温度数据到主题"home/living-room/temperature",而显示设备订阅了这个主题,那么显示设备就会在温度发生变化时接收到有关客厅温度的消息。
MQTT的主题是一种用于在MQTT通信中标识和组织消息的机制,它使得设备可以基于感兴趣的主题来发布和订阅消息,实现了灵活的发布/订阅模式。
1.2.4负载(Payload)
MQTT的负载(Payload)是指在消息中实际传输的数据部分,也就是消息的内容。在MQTT通信中,发布者发布消息时,消息的负载部分包含了具体的信息,而订阅者在接收消息时会解析这个负载来获取所需的数据。
负载可以是任何形式的数据,例如文本、二进制数据、JSON、XML等,取决于应用的需求和数据类型。在物联网应用中,通常会将传感器数据、设备状态、命令等放置在消息的负载中。
举例来说,假设有一个温度传感器通过MQTT发布温度数据到主题"home/living-room/temperature"。在这个场景中,消息的负载就是实际的温度值,可以是一个数值,比如20°C。订阅者在接收到这个消息后,会从负载中解析出温度数据,然后根据需要进行相应的处理,比如将温度显示在用户界面上。
总之,MQTT的负载是消息中传输的实际数据部分,它可以是各种类型的信息,用于在发布者和订阅者之间传递具体的应用数据。
1.2.5会话(Session)
MQTT(Message Queuing Telemetry Transport)的会话是指客户端与MQTT代理(或服务器)之间的持久性连接,用于在通信过程中传递消息。会话允许客户端与服务器之间进行可靠的、双向的消息传递,并且可以在需要的时候重新连接,以保持持久性通信。
MQTT会话的一些重要概念包括:
-
保持连接(Keep Alive): MQTT允许客户端和代理之间维持一个保持连接的机制。客户端可以指定一个保持连接的时间间隔,通常以秒为单位。在这个时间间隔内,客户端需要定期向代理发送一个称为PINGREQ的心跳消息,以表明它仍然活跃。如果代理在一定时间内没有收到PINGREQ消息,就会认为客户端断开连接,并关闭该连接。
-
持久性会话(Persistent Session): 客户端可以选择创建持久性会话。这意味着如果客户端断开连接,代理会保留客户端的订阅信息和消息队列。当客户端重新连接时,它可以继续接收之前订阅的主题的消息,而不会丢失任何消息。持久性会话在物联网设备断线重连后能够确保不会错过关键的信息。
-
清除会话(Clean Session): 客户端可以选择创建非持久性会话,也就是所谓的“清除会话”。在这种情况下,当客户端断开连接后,代理会删除客户端的订阅信息和消息队列。当客户端重新连接时,它将不会收到之前订阅的主题的消息。清除会话适用于临时连接,比如获取一些即时数据而不需要保留历史信息。
-
QoS级别(Quality of Service): MQTT支持不同的QoS级别,用于确保消息的可靠性。QoS 0表示消息仅发送一次,可能会丢失;QoS 1表示消息至少传递一次,但可能重复;QoS 2表示消息恰好传递一次,确保了消息不会重复。
在MQTT会话中,客户端通过发送CONNECT消息来建立连接,之后进行订阅、发布和接收消息。会话状态可以是活跃的,也可以是已断开的,这取决于客户端和代理之间的连接状态。
MQTT的会话机制允许客户端与代理之间建立可靠的连接,支持持久性会话以及保持连接的机制,确保在物联网应用中能够有效地进行消息传递。
二.MQTT协议特点
2.1订阅与发布
MQTT协议采用发布/订阅(Publish/Subscribe)模式,这是一种用于消息传递的模式。在这个模式下,设备之间通过主题(Topic)进行通信,而不是直接建立点对点的连接。设备可以发布消息到特定的主题,其他设备可以订阅这些主题以接收相应的消息。
发布(Publish): 发布者(Publisher)将消息发布到一个特定的主题上。消息可以是任何类型的数据,如传感器读数、状态更新等。
订阅(Subscribe): 订阅者(Subscriber)通过订阅特定的主题来表示它对该主题上的消息感兴趣。一旦有新消息发布到该主题,订阅者将会接收到这些消息。
下面是一个示例,演示了如何使用MQTT协议进行发布和订阅:
-
设备A - 发布者:
设备A要发布温度传感器的读数。import paho.mqtt.client as mqtt broker_address = "mqtt.example.com" # MQTT broker的地址 client = mqtt.Client("DeviceA") client.connect(broker_address) topic = "sensors/temperature" temperature = 25.5 client.publish(topic, str(temperature))
-
设备B - 订阅者:
设备B订阅温度传感器的主题,以接收温度读数。import paho.mqtt.client as mqtt broker_address = "mqtt.example.com" # MQTT broker的地址 client = mqtt.Client("DeviceB") def on_message(client, userdata, message): print("Received message:", message.payload.decode()) client.on_message = on_message client.connect(broker_address) topic = "sensors/temperature" client.subscribe(topic) client.loop_forever()
在这个示例中,设备A发布温度传感器的读数到主题sensors/temperature
,而设备B订阅相同的主题以接收温度读数。一旦设备A发布了新的温度读数,设备B的订阅者将会收到消息并执行定义的on_message
函数来处理消息。
需要注意的是,示例中使用了 paho.mqtt.client
模块来实现MQTT通信。实际应用中,你需要指定正确的MQTT broker地址、设置合适的主题、配置适当的QoS级别等。
2.2 QoS
MQTT中的QoS(Quality of Service,服务质量)是指在消息传递过程中保证消息传递的可靠性和确保消息达到目标设备的程度。MQTT定义了三个不同的QoS级别,分别为0、1和2,它们在消息发布和传递过程中提供了不同程度的保证和确认。
1.QoS 0:最多一次传递(At most once)
在QoS 0级别下,发布者将消息发布到主题后,不会接收到任何确认或反馈。消息将仅仅发布一次,不会进行重传,也不会保留在中间代理服务器上。这意味着消息可能会在传递过程中丢失或重复。
2.QoS 1:最少一次传递(At least once)
在QoS 1级别下,发布者将消息发布到主题后,会等待接收到确认(PUBACK)消息。如果确认丢失,发布者会重发消息。接收者在收到消息后发送确认,确保消息至少传递一次给订阅者。这样可以确保消息不会丢失,但可能会出现重复传递。
3.QoS 2:正好一次传递(Exactly once)
QoS 2级别提供了最高的消息传递保证。在这个级别下,发布者和订阅者之间会进行更多的交互,以确保消息只传递一次。发布者首先发送消息,并等待收到订阅者的确认(PUBREC),然后发布者再发送一个释放确认(PUBREL)。最后,订阅者发送一个完成确认(PUBCOMP)。这种级别确保了消息仅会传递一次,但由于需要多次交互,会增加一定的通信开销。
在选择QoS级别时,需要考虑网络的可靠性和消息传递的可靠性之间的权衡。较低的QoS级别可能会提高传输效率,但可能会导致消息丢失。较高的QoS级别能够确保消息的可靠传递,但会增加通信的复杂性和开销。
例如,在物联网应用中,对于一些实时性不高、重要性较低的传感器数据,可以选择QoS 0级别,以降低通信开销。而对于一些重要的控制命令或状态更新,可能会选择QoS 1或QoS 2级别,以确保消息的可靠传递。
三.MQTT数据包结构
MQTT(Message Queuing Telemetry Transport)协议的数据包结构通常由固定头部和可变头部组成,以及可能包含的负载(Payload)。
- 固定头部(Fixed Header): 数据包的固定头部是每个MQTT消息必须包含的部分,它包括了一些控制信息,例如消息类型、QoS级别、重发标志等。固定头部的位数是固定的,根据不同的消息类型,它占据不同的比特位。
- 可变头部(Variable Header): 可变头部包含了一些与消息类型相关的附加信息。根据不同的消息类型,可变头部的内容会有所不同。例如,订阅消息的可变头部可能包含订阅的主题、QoS级别等信息。
- 负载(Payload): 消息的负载部分是可选的,它包含了实际要传输的数据。这部分内容的格式和类型取决于应用的需求和消息的用途。例如,如果发布的是温度数据,那么负载可能是一个数值,如果发布的是JSON格式的消息,那么负载就是JSON数据。
MQTT数据格式如下所示:
3.1MQTT固定头
固定头存在所有的MQTT包中,其结构如下:
3.1.1消息类型(Message Type)
这个字段指示了消息的类型,例如CONNECT、PUBLISH、SUBSCRIBE、UNSUBSCRIBE等。不同的消息类型在协议中有不同的数值表示。
名称 | 值 | 流方向 | 描述 |
Reserved | 0 | 不可用 | 保留位 |
CONNECT | 1 | 客户端到服务器 | 客户端请求连接到服务器 |
CONNACK | 2 | 服务器到客户端 | 连接确认 |
PUBACK | 4 | 双向 | 发布确认 |
PUBREC | 5 | 双向 | 发布收到(保证第1部分到达) |
PUBREL | 6 | 双向 | 发布释放(保证第2部分到达) |
PUBCOMP | 7 | 双向 | 发布完成(保证第3部分到达) |
SUBSCRIBE | 8 | 客户端到服务器 | 客户端请求订阅 |
SUBACK | 9 | 服务器到客户端 | 订阅确认 |
UNSUBSCRIBE | 10 | 客户端到服务器 | 请求取消订阅 |
UNSUBACK | 11 | 服务器到客户端 | 取消订阅确认 |
PINGREQ | 12 | 客户端到服务器 | PING请求 |
PINGRESP | 13 | 服务器到客户端 | PING应答 |
DISCONNECT | 14 | 客户端到服务器 | 中断连接 |
Reserved | 15 | 不可用 | 保留位 |
3.1.2标志位(Flags)
标志位用来表示一些附加信息,根据消息类型的不同,标志位可能包括不同的标志,如QoS级别、保持连接标志、重发标志等
数据包 | 标志位 | Bit3 | Bit2 | Bit1 | Bit0 |
CONNECT | 保留位 | 0 | 0 | 0 | 0 |
CONNACK | 保留位 | 0 | 0 | 0 | 0 |
PUBLISH | MQTT 3.1.1使用 | DUP1 | QoS2 | QoS2 | RETAIN3 |
PUBACK | 保留位 | 0 | 0 | 0 | 0 |
PUBREC | 保留位 | 0 | 0 | 0 | 0 |
PUBREL | 保留位 | 0 | 0 | 0 | 0 |
PUBCOMP | 保留位 | 0 | 0 | 0 | 0 |
SUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
SUBACK | 保留位 | 0 | 0 | 0 | 0 |
UNSUBSCRIBE | 保留位 | 0 | 0 | 0 | 0 |
UNSUBACK | 保留位 | 0 | 0 | 0 | 0 |
PINGREQ | 保留位 | 0 | 0 | 0 | 0 |
PINGRESP | 保留位 | 0 | 0 | 0 | 0 |
DISCONNECT | 保留位 | 0 | 0 | 0 | 0 |
- DUP:发布消息的副本。用来在保证消息的可靠传输,如果设置为 1,则在下面的变长中增加MessageId,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。
- QoS发布消息的服务质量。
- RETAIN:发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。
3.1.3剩余长度(Remaining Length)
这个字段指示了剩余数据的长度,它用变长编码方式表示。剩余长度包括可变头部和负载部分的长度。
3.2MQTT可变头
MQTT(Message Queuing Telemetry Transport)协议的可变头部是每个MQTT消息中的一个部分,位于固定头部之后,包含了一些与消息类型相关的附加信息。可变头部的内容根据不同的消息类型而不同,它提供了关于消息的更多上下文和控制信息。
可变头部通常包含以下一些字段,这些字段的具体含义会根据消息类型的不同而有所变化:
-
协议名称(Protocol Name): 这个字段指定了使用的协议名称,通常为"MQTT"。它用于识别消息是否是有效的MQTT消息。
-
协议级别(Protocol Level): 协议级别指示了所使用的MQTT协议的版本。不同的协议级别可能对应不同的协议特性和行为。
-
标志位(Flags): 可变头部的标志位提供了关于消息的额外信息。例如,在连接消息中,标志位用于指示是否清除会话、是否支持保持连接等。
-
保持连接时间(Keep Alive): 这个字段用于指定客户端和服务器之间保持连接的时间间隔。如果在这个时间间隔内没有任何通信活动,服务器可能会断开连接。
-
消息标识符(Message Identifier): 某些消息类型,例如PUBLISH、PUBACK、PUBREC等,可能需要一个消息标识符来进行消息的确认和匹配。
-
订阅标识符(Subscription Identifier): 在订阅消息中,可变头部可能包含一个订阅标识符,用于唯一标识订阅请求。
可变头部的结构和字段取决于消息类型,并且不同的消息类型可能会有不同的可变头部内容。很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有:PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK
3.3Payload消息体
消息的负载部分是可选的,它包含了实际要传输的数据。这部分内容的格式和类型取决于应用的需求和消息的用途。例如,如果发布的是温度数据,那么负载可能是一个数值,如果发布的是JSON格式的消息,那么负载就是JSON数据。
只有CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息有消息体:
- CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码
- SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。
- SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。
- UNSUBSCRIBE,消息体内容是要订阅的主题。
MQTT参考文档:
链接:https://pan.baidu.com/s/1PWoCm5nVZz_9s_Wzz36o-A?pwd=7897
提取码:7897