3. 通信协议选择:HTTP/HTTPS、MQTT、CoAP协议对比与选型
说到OTA升级,通信协议的选择是个绕不开的话题。我见过不少团队,硬件做得很扎实,结果在协议选型上栽了跟头——要么升级太慢,要么动不动就断连。说白了,协议选错了,后面全是坑。
今天咱们就聊聊三种主流的物联网协议:HTTP/HTTPS、MQTT、CoAP。我会结合自己的项目经验,讲讲它们各自适合什么场景,以及基于以太网时该怎么选。
3.1 三大协议核心对比
先上一张对比表,方便你快速建立认知。这张表是我根据实际项目经验整理的,不是网上随便抄的。
| 特性 | HTTP/HTTPS | MQTT | CoAP |
|---|---|---|---|
| 传输层 | TCP | TCP | UDP |
| 消息模型 | 请求/响应 | 发布/订阅 | 请求/响应 + 观察 |
| 头部开销 | 大(几百字节) | 小(2字节起) | 极小(4字节起) |
| 安全性 | HTTPS(TLS) | TLS + 用户名密码 | DTLS |
| QoS支持 | 无原生支持 | 3级(0/1/2) | 确认/非确认 |
| 适用场景 | 大文件、Web生态 | 实时控制、消息推送 | 低功耗、受限设备 |
3.2 HTTP/HTTPS:最熟悉的陌生人
HTTP大家肯定都用过。做OTA升级时,很多人第一反应就是HTTP。为什么?因为简单啊。服务器端随便搭个Nginx,客户端用libcurl或者ESP32的HTTP库,几行代码就能跑起来。
但我得提醒你一句:HTTP在物联网场景下,其实没那么友好。
举个例子。我之前做一个智能网关的OTA项目,设备数量大概5000台。一开始用的就是HTTPS,结果升级高峰期服务器连接数直接爆了。每个设备下载固件都要建立TCP连接,三次握手、TLS握手、下载、四次挥手...这一套下来,服务器压力非常大。
而且HTTP是请求/响应模式,服务器没法主动推送升级通知。你得让设备定时轮询——「有新固件吗?」「没有。」「有新固件吗?」「没有。」...你想想看,这得浪费多少流量和电量。
那HTTP就一无是处吗?也不是。
如果你的设备数量不多(几百台以内),或者固件包特别大(几十MB以上),HTTP反而是好选择。因为HTTP的分块传输、断点续传这些能力,MQTT和CoAP都比不了。我在做车载娱乐系统OTA时,固件包动辄几百MB,这时候只能用HTTPS。
我的建议:设备数量少、固件包大、对实时性要求不高时,选HTTPS。反之,设备多、固件小、需要实时推送时,别用HTTP。
3.3 MQTT:物联网的「消息快递员」
MQTT是我个人最喜欢的物联网协议。它的设计哲学很纯粹——轻量、可靠、双向通信。
MQTT的核心是发布/订阅模型。设备订阅一个主题,服务器往这个主题发消息,所有订阅的设备都能收到。这天然适合OTA升级的场景:服务器发布「新固件可用」的通知,设备收到后开始下载。
我记得有个项目是做智能楼宇的照明控制,2000多个节点。如果用HTTP,服务器得维护2000个连接,想想就头疼。换成MQTT后,所有节点只连一个Broker,服务器只管往主题里发消息就行。架构瞬间清爽了。
MQTT的QoS机制也很实用。OTA升级时,我一般这么用:
- QoS 0:发送升级通知(丢了也无所谓,设备下次轮询也能知道)
- QoS 1:传输固件元数据(必须收到,但允许重复)
- QoS 2:传输升级确认指令(必须且仅一次)
不过MQTT也有短板。它基于TCP,对网络质量要求高。如果设备经常断线重连,MQTT的会话恢复机制虽然能兜底,但实现起来挺麻烦的。另外,MQTT不太适合传大文件——虽然技术上可以,但实际用起来你会发现,Broker的内存和带宽很快就扛不住了。
避坑指南:我曾经在MQTT里直接传固件包,结果Broker OOM了。后来改成MQTT只传下载链接,设备收到后用HTTP下载固件。这种「MQTT通知 + HTTP下载」的组合拳,在实际项目中非常实用。
3.4 CoAP:为受限设备而生
CoAP可能有些朋友不太熟悉。它本质上是HTTP的UDP版本,专门为资源受限的设备设计的。
CoAP的头部只有4个字节,比HTTP小了两个数量级。而且它支持观察模式(Observe),设备可以「订阅」一个资源,服务器有变化时主动推送。这跟MQTT的发布/订阅有点像,但更轻量。
我在做传感器网络项目时用过CoAP。那些设备只有几十KB的RAM,跑MQTT库都费劲,但CoAP跑起来很轻松。不过CoAP也有个硬伤——基于UDP,可靠性得自己保证。虽然CoAP有确认机制,但在网络拥塞时,丢包率会比TCP高不少。
对于OTA升级来说,CoAP适合那些对功耗和内存极度敏感的设备。但说实话,如果你的设备跑的是以太网,一般不会太缺资源。所以CoAP在以太网场景下用得不多。
3.5 基于以太网的协议选型建议
好了,三种协议都聊完了。那在以太网环境下,到底该怎么选?
我的经验是:看设备资源,看升级频率,看网络规模。
- 设备资源充足(几百KB RAM以上):首选MQTT + HTTP组合。MQTT负责控制面(通知、状态上报),HTTP负责数据面(固件下载)。这是目前工业界最成熟的方案。
- 设备资源中等(几十KB RAM):纯MQTT方案。固件包控制在1MB以内,直接通过MQTT的二进制payload传输。注意Broker的配置要调优。
- 设备资源紧张(几KB RAM):CoAP + 块传输(Block-wise Transfer)。每次只传一小块,设备慢慢拼起来。但说实话,以太网设备很少这么拮据。
注意:不管选哪种协议,一定要考虑安全性。以太网环境比局域网复杂得多,攻击面更大。HTTPS、MQTT over TLS、CoAP over DTLS,至少选一个。我见过有人图省事用明文HTTP做OTA,结果固件被篡改,设备全部变砖...那场面,惨不忍睹。
3.6 自定义应用层协议设计思路
有时候,现成的协议满足不了需求。比如你需要极致的传输效率,或者有特殊的业务逻辑。这时候就得自己设计应用层协议了。
我设计自定义协议时,一般遵循这几个原则:
- 固定头部 + 可变载荷:头部固定长度,包含魔数、版本、命令、长度、校验等字段。载荷根据命令类型变化。
- 命令码设计:用1字节或2字节表示命令。比如0x01表示查询版本,0x02表示开始升级,0x03表示传输数据块。
- 分片与重组:固件包太大时,分成多个数据块传输。每个块带序号和总块数,接收端按序号重组。
- 确认与重传:每个数据块都需要确认。超时未确认就重传,最多重传3次。
下面是我之前一个项目里用的协议头部结构,供你参考:
// 自定义OTA协议头部(共8字节)
typedef struct {
uint16_t magic; // 魔数,固定0x5A5A
uint8_t version; // 协议版本
uint8_t cmd; // 命令码
uint16_t length; // 载荷长度
uint8_t checksum; // 头部校验和
} __attribute__((packed)) ota_header_t;
自定义协议的好处是灵活,坏处是得自己处理所有细节。我建议你:除非有非常特殊的理由,否则优先用现成协议。MQTT和HTTP的生态太成熟了,轮子没必要再造一遍。
总结一下:协议选型没有银弹。HTTP适合大文件、小规模;MQTT适合控制面、大规模;CoAP适合超低资源设备。以太网环境下,我推荐MQTT + HTTP的组合。如果非要自定义协议,记得把头部设计得紧凑一些,校验一定要做。
下一章咱们聊聊具体的固件包结构和签名机制。这部分我踩过不少坑,到时候详细跟你说。