MQTT协议基本流程、原理

MQTT是一种轻量级的发布/订阅消息协议,常用于物联网和M2M通信。它包括C/S架构,支持三种QoS级别确保消息传递的可靠性。MQTT协议中有如PUBLISH、SUBSCRIBE、PUBACK等控制报文,用于信息的发布、订阅和确认。订阅包含主题过滤器和QoS,主题名是应用消息的标签。QoS0、QoS1和QoS2分别对应不同的消息传递保障。在连接建立、信息发送和订阅过程中,MQTT通过特定的控制报文确保数据交互的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本概念

MQTT是一个C/S架构的发布/订阅模式的消息传输协议
基本设计思想是轻巧、开放、简单、规范,易于实现。
这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT)。

MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

现在基本上在IoT环境中都是使用的MQTT协议。

在MQTT协议中的一些关键词和基本概念

订阅 Subscription

订阅包含一个主体过滤器(Topic Filter)和一个最大的服务质量(Qos)等级。订阅和单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。

主题名 Topic Name

附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。

主题过滤器 Topic Filter

订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。

会话 Session

客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端和服务端的多个连续网络连接间扩展。

控制报文 MQTT Control Packet

通过网络连接发送的信息数据包。类似于ICMP,MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。

服务器 Broker

在消息订阅模型中充当服务器的角色, 类似于送信的邮差。

Qos 消息服务质量机制

通过使用Qos机制,来保证通信的质量,也就是发送connect报文的次数时间,有以下几种情况:

  1. QoS0: “至多1次”
    消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。1次发送失败后,不再重新发送。
    这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了

  2. QoS1:“至少1次”
    确保信息到达,发送1次对方没有确认接收后,会重新发送,但是可能会出现多次接收的情况

  3. QoS2:“至多一次”
    确保信息到达1次且仅到达1次。在一些要求比较严格的计费系统中,可以使用此级别。在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到1次。

对于QoS值的确认,是基于二者客户端的的最低值,例如A 客户端使用的是QoS2,B客户端使用的是QoS1,那么服务器最后使用的就是QoS1。

MQTT协议中的方法

MQTT协议中定义了一些方法(也被称为动作),来于表示对确定资源所进行操作。这个资源可以代表预先存在的数据或动态生成数据,这取决于服务器的实现。通常来说,资源指服务器上的文件或输出。主要方法有:

在这里插入图片描述

MQTT协议中的通信过程

建立连接

在建立连接时,首先客户端往服务器发送CONNECT连接建立报文。
规定在网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文。

在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接。在这个报文中包含了遗嘱信息、keep alive等标志位

在服务器接收到CONNECT报文后,服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文必须是CONNACK。

如果客户端在合理的时间内没有收到服务端的CONNACK报文,客户端应该关闭网络连接。合理的时间取决于应用的类型和通信基础设施。

在CONNACK报文中,主要包含连接确认标志和返回码,但是不包含有效载荷

具体见流程图:

在这里插入图片描述

发送信息流程

在发送信息的流程中主要有几种报文:
PUBLISH – 发布消息:

PUBLISH控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息。在信息中主要的标志位是DUP(重发标志位)、QoS(服务质量标识)、Topic Nmae(主题名)等。
有了PUBLISH报文后,就可以发送QoS为0的报文:
对于QoS为0的情况,发起方在发送PUBLIC 报文后便由Broker发送给接收方,中间不再做任何处理。

对于QoS为1的报文,还需要另外1个报文类型参与

PUBACK –发布确认:

PUBACK报文是对QoS 1等级的PUBLISH报文的响应。

有了PUBACK报文后,就可以完成QoS为1 的报文发送。

对于QoS为1的情况,发起方在发送PUBLIC 报文后便由Broker发送给接收方,接收方收到后,会回复PUBACK报文,具体流程如图:

在这里插入图片描述

要实现QoS为2的信息发布,还需要另外3个报文:
PUBREC – 发布收到(QoS 2,第一步)

PUBREC报文是对QoS等级2的PUBLISH报文的响应。它是QoS 2等级协议交换的第二个报文。

PUBREL – 发布释放(QoS 2,第二步)

PUBREL报文是对PUBREC报文的响应。它是QoS 2等级协议交换的第三个报文。

PUBCOMP – 发布完成(QoS 2,第三步)

PUBCOMP报文是对PUBREL报文的响应。它是QoS 2等级协议交换的第四个也是最后一个报文。

对于QoS为2的信息发布,需要:

  1. 发送方发送PUBLIC报文
  2. 接收方接收到PUBLIC后回复PUBREC报文
  3. 发送方接收到PUBREC报文回复PUBREL报文
  4. 接收方接收到PUBREL后回复PUBCOMP报文

结束。
对于QoS为2的流程,明显多了几个步骤,因此对于该类型的信息发布有较多的流量消耗
具体流程见图:

在这里插入图片描述

消息订阅流程

订阅相关报文:
SUBSCRIBE - 订阅主题

客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。
每个订阅注册客户端关心的一个或多个主题。

SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据QoS等级发送应用消息给客户端。

其主题相关数据放在了有效载荷上,并且还包含一个主题过滤器列表。

SUBACK – 订阅确认

在接收到SUBCRIBE报文后,服务端发送SUBACK报文给客户端,用于确认它已收到并且正在处理SUBSCRIBE报文。
SUBACK报文包含一个返回码清单,允许的返回码值:

  • 0x00 - 最大QoS 0
  • 0x01 - 成功 – 最大QoS 1
  • 0x02 - 成功 – 最大 QoS 2
  • 0x80 - Failure 失败
    它们指定了SUBSCRIBE请求的每个订阅被授予的最大QoS等级。

订阅完成后客户端需要传输对应的信息时,会在信息上添加上主题,添加后通过PUBLIC 发送到服务端,服务端再根据主题与订阅情况发送给对应的客户端。

基于以上两个报文,订阅的流程如下:
在这里插入图片描述
同样的,有了订阅流程便还有取消订阅流程,相关的有两个报文:
UNSUBSCRIBE –取消订阅

客户端发送UNSUBSCRIBE报文给服务端,用于取消订阅主题。

关于想要取消的订阅主题列表在有效载荷中,且规定取消订阅主题必须至少包含1个取消订阅主题。

UNSUBACK – 取消订阅确认

服务端收到UNSUBSCRIBE报文后,发送UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文。

对于取消订阅确认报文,没有有效载荷。
流程跟订阅类似:

在这里插入图片描述


参考资料:
MQTT官方文档

### MQTT协议连接OneNet的工作原理及实现机制 #### 一、MQTT协议概述 MQTT(Message Queuing Telemetry Transport)是一种基于TCP/IP协议栈构建的异步通信消息协议,采用客户端-服务器架构以及发布/订阅模式[^2]。该协议由Andy Stanford-Clark和Arlen Nipper于1999年创建,旨在解决低带宽、高延迟或不可靠网络环境下的设备间高效通信问题。 #### 二、OneNet平台介绍 OneNet是中国移动推出的一个物联网开放平台,提供丰富的API和服务来帮助开发者快速搭建物联网应用。通过支持多种主流物联网协议(如CoAP、HTTP、LWM2M),其中也包括MQTT协议,使得各种类型的终端设备能够轻松接入并管理其数据流[^3]。 #### 三、MQTT协议连接OneNet的核心原理 当使用MQTT协议将设备连接到OneNet时,整个过程遵循标准的MQTT流程,并结合OneNet的具体需求进行了适配: 1. **注册与配置** 设备需先在OneNet平台上完成注册操作,获取唯一的`ProductKey`和`DeviceName`作为身份标识符。此外还需要设置密钥或其他形式的身份验证参数用于后续的安全校验。 2. **建立TCP连接** 客户端依据指定域名或者IP地址向OneNet服务器发起TCP握手请求,在成功建立稳定通道之后方可继续下一步动作。 3. **发送CONNECT报文** 这一步骤标志着正式进入MQTT会话阶段。客户端按照既定格式构造包含必要字段(例如ClientID, UserName, Password等) 的CONNECT包提交给Broker即OneNet云端实例处理。 4. **主题订阅(SUBSCRIBE)/发布(PUBLISH)** - 对于需要接收来自其他节点推送过来的信息而言,则要执行SUBSCRIBE命令告知目标Topic范围;反之如果打算主动分享某些资源则运用PUBLISH方法广播出去相应负载内容。 - OneNet允许用户自定义多个Topics以便分类整理各类事件通知或是传感数值更新情况等等。 5. **保持心跳检测(MQTT Keep Alive Mechanism)** 为了避免长时间无交互而导致断线重连现象发生,双方约定好一定周期内的PINGREQ/PINGRESP交换行为以维持在线状态。 6. **异常处理与重新上线策略** 鉴于实际运行环境中可能存在意外掉电或者其他干扰因素影响持续运作效果,因此有必要预先规划一套完善的错误恢复方案确保服务稳定性。 #### 四、具体实现案例分析——ESP8266模块对接实践 以下是一个典型的例子展示如何借助Arduino IDE编程环境下驱动搭载WiFi功能芯片组的产品比如ESP8266系列型号达成上述目的: ```cpp #include <PubSubClient.h> #include <ESP8266WiFi.h> // 替换为您的Wi-Fi SSID和密码 const char* ssid = "Your_SSID"; const char* password = "Your_PASSWORD"; // 替换为您自己的OneNET信息 #define ONE_NET_SERVER IPAddress(183, 230, 175, 17) #define PORT 6002 #define PRODUCT_KEY "your_product_key" #define DEVICE_NAME "your_device_name" #define API_KEY "your_api_key" WiFiClient espClient; PubSubClient client(espClient); void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); } bool connectToServer(){ String clientId = "ESP8266Client-" + String(random(0xffff), HEX); if(client.connect(clientId.c_str(),PRODUCT_KEY ":" DEVICE_NAME ,API_KEY)){ return true ; }else{ return false ; } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { if(connectToServer()){ Serial.println("Connected To Server!"); // 订阅某个topic client.subscribe("/sys/a/b/c"); } else { Serial.println("Failed to Connect..."); delay(5000); } } } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i=0;i<length;i++) { Serial.print((char)payload[i]); } Serial.println(); // 处理接收到的消息... } void loop() { if(!client.connected()){ reconnect(); } client.loop(); static unsigned long lastMsgTime = millis(); const unsigned long msgInterval = 10 * 1000; // 每隔十秒发送一次测试数据 if ((millis()-lastMsgTime)>msgInterval){ float temperatureValue=random(-20,50)*0.1f;//模拟温度读数 StaticJsonDocument<200> doc; doc["temperature"]=temperatureValue; char jsonBuffer[200]; serializeJson(doc,jsonBuffer,sizeof(jsonBuffer)); bool successFlag=client.publish("/sys/a/b/data",jsonBuffer); if(successFlag){ Serial.printf("Published Data:%s\n",jsonBuffer); }else{ Serial.println("Publish Failed!"); } lastMsgTime=millis(); } } setup(){ setup_wifi(); client.setServer(ONE_NET_SERVER,PORT); client.setCallback(callback); } loop(){} ``` 以上代码片段展示了基本框架结构,涵盖了从初始化硬件设施直到最终形成闭环反馈链路全过程的关键环节[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值