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. 命令码设计:用1字节或2字节表示命令。比如0x01表示查询版本,0x02表示开始升级,0x03表示传输数据块。
  3. 分片与重组:固件包太大时,分成多个数据块传输。每个块带序号和总块数,接收端按序号重组。
  4. 确认与重传:每个数据块都需要确认。超时未确认就重传,最多重传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的组合。如果非要自定义协议,记得把头部设计得紧凑一些,校验一定要做。

下一章咱们聊聊具体的固件包结构和签名机制。这部分我踩过不少坑,到时候详细跟你说。