1. 物联网与MQTT协议概述
各位同学好,我是你们这期课程的讲师。咱们今天正式开篇,聊聊物联网和MQTT协议。说实话,我做了十几年嵌入式开发,从最早的8051单片机一路做到现在的ESP32,感触最深的就是通信协议的变化。以前设备之间通信,串口、I2C、SPI这些板级协议就够用了。但到了物联网时代,设备要上云,要远程控制,传统的协议就有点力不从心了。
MQTT正是在这个背景下诞生的。它轻量、省带宽、支持低带宽和不稳定网络,特别适合资源受限的嵌入式设备。我个人习惯把MQTT比作物联网世界的“信使”——它不关心你传的是什么数据,只负责把数据可靠地送到目的地。
1.1 物联网架构简介
先看一张图,了解一下物联网的整体架构。这样你后面学MQTT时,就知道它处在哪个位置了。
物联网四层架构(从下到上):
- 感知层:传感器、执行器、RFID标签等。负责采集数据和执行命令。
- 网络层:Wi-Fi、LoRa、NB-IoT、4G/5G等。负责数据传输。
- 平台层:云平台(如阿里云IoT、AWS IoT)、MQTT Broker。负责设备管理、数据存储、规则引擎。
- 应用层:手机App、Web仪表盘、业务系统。负责数据展示和业务逻辑。
MQTT协议主要工作在网络层和平台层之间。它不关心底层是Wi-Fi还是4G,只负责把应用层的数据打包成标准格式,通过TCP/IP传输。
我的经验:很多初学者容易把MQTT和HTTP混为一谈。其实它们分工不同——HTTP是“请求-响应”模式,适合浏览器看网页;MQTT是“发布-订阅”模式,适合设备之间实时通信。你想想看,如果每个传感器都像HTTP那样频繁建立连接,那带宽和电量根本扛不住。
1.2 MQTT协议诞生背景
MQTT全称是Message Queuing Telemetry Transport(消息队列遥测传输)。它最早是IBM在1999年开发的,目的是用于石油管道监控。那时候卫星通信带宽极低,一个数据包可能只有几十字节,传统的HTTP头就有几百字节,根本没法用。
我记得2015年第一次接触MQTT时,是在一个智能农业项目里。客户要求用2G网络传输土壤湿度数据,每5分钟上报一次。如果用HTTP,光TCP三次握手就要消耗大量流量,而且2G网络延迟高、不稳定。后来换成MQTT,流量直接降了80%,而且断线重连机制让系统稳定了很多。
MQTT后来在2014年成为OASIS标准,2016年发布MQTT 5.0版本。现在几乎所有主流云平台都支持MQTT,包括阿里云、华为云、AWS、Azure。
1.3 MQTT vs HTTP vs CoAP
很多同学会问:为什么物联网不用HTTP?CoAP又是什么?我整理了一张对比表,你看完就明白了。
| 特性 | MQTT | HTTP | CoAP |
|---|---|---|---|
| 通信模型 | 发布/订阅 | 请求/响应 | 请求/响应 + 观察者 |
| 传输层 | TCP | TCP | UDP |
| 报文开销 | 最小2字节 | 几百字节 | 4字节 |
| QoS支持 | 3级(0/1/2) | 无原生QoS | 确认/非确认 |
| 实时性 | 高(长连接推送) | 低(轮询) | 中 |
| 适用场景 | 传感器、远程监控、推送 | Web页面、REST API | 极低功耗设备、受限网络 |
避坑指南:我曾经在一个项目中,用HTTP轮询方式采集100个传感器的数据。结果服务器压力巨大,而且传感器电池两天就没电了。后来换成MQTT,电池续航直接提升到3个月。所以选协议时,一定要考虑功耗和网络开销。
说白了,HTTP是为“人看网页”设计的,MQTT是为“机器对话”设计的。CoAP虽然更轻量,但基于UDP,可靠性不如MQTT。我个人习惯:如果设备有Wi-Fi或以太网,优先用MQTT;如果设备是电池供电且网络极差,可以考虑CoAP。
1.4 MQTT核心特性
MQTT有三大核心特性:发布/订阅模型、QoS等级、遗嘱消息。这三个特性是MQTT的灵魂,也是你后面写代码时必须理解的内容。
1.4.1 发布/订阅模型
传统HTTP是“客户端-服务器”模式,客户端主动请求,服务器被动响应。MQTT不一样,它引入了Broker(代理)的概念。
- 发布者(Publisher):发送消息到某个主题(Topic)。比如温度传感器发布数据到
sensor/temperature。 - 订阅者(Subscriber):订阅感兴趣的主题。比如手机App订阅
sensor/temperature,就能收到温度数据。 - Broker:负责接收发布者的消息,并转发给所有订阅者。
这样做的好处是:发布者和订阅者完全解耦。发布者不需要知道谁在订阅,订阅者也不需要知道谁在发布。你想想看,如果100个传感器都要和手机App直连,那连接数就是100×100=10000条。有了Broker,传感器只连Broker,App也只连Broker,连接数降到200条。
1.4.2 QoS等级
QoS(Quality of Service)是MQTT保证消息可靠性的机制。它有三个等级:
| 等级 | 名称 | 发送次数 | 可靠性 | 适用场景 |
|---|---|---|---|---|
| QoS 0 | 至多一次 | 1次(不确认) | 最低 | 传感器高频数据(如温度),丢一帧无所谓 |
| QoS 1 | 至少一次 | 至少1次(确认重传) | 中等 | 控制指令(如开灯),允许重复 |
| QoS 2 | 恰好一次 | 4次握手 | 最高 | 计费、支付等关键数据 |
我的建议:在ESP32项目中,大部分场景用QoS 0或QoS 1就够了。QoS 2虽然可靠,但开销大、延迟高。我曾经在一个智能门锁项目里用了QoS 2,结果因为网络抖动,消息重传导致门锁响应延迟了3秒。后来改成QoS 1,配合业务层的去重逻辑,效果反而更好。
1.4.3 遗嘱消息
遗嘱消息(Will Message)是MQTT一个非常实用的特性。它允许客户端在连接Broker时,预先设置一条“遗言”。如果客户端异常断开(比如掉电、断网),Broker会自动帮它发布这条遗言。
举个例子:你有一个烟雾报警器,它正常时每隔10秒上报一次“一切正常”。如果它突然掉线了,Broker就会发布遗嘱消息“设备离线,可能发生火灾”。其他订阅者收到这条消息后,可以立即触发报警。
避坑指南:我曾经在一个项目中忘了设置遗嘱消息,结果设备掉线后,服务器一直以为设备还在线。直到用户投诉说设备没反应,我才发现设备早就离线了。从那以后,我每个项目都会加上遗嘱消息,哪怕只是简单的“设备离线”通知。
遗嘱消息的配置很简单,在连接Broker时设置三个参数:
// 伪代码示例
client.connect({
willTopic: "device/status", // 遗嘱主题
willPayload: "offline", // 遗嘱内容
willQoS: 1, // 遗嘱QoS
willRetain: true // 是否保留
});