嵌入式网络协议实战:MQTT、HTTP、CoAP
IoT 项目离不开网络通信。本文介绍嵌入式开发中最常用的网络协议,以及 GitHub 上的优质实现代码,帮助你快速实现设备联网。
一、协议对比与选型
| 协议 | 传输层 | 特点 | 适用场景 |
| MQTT | TCP | 发布/订阅、轻量 | 设备上报、远程控制 |
| HTTP | TCP | 通用、RESTful | Web API、配置管理 |
| CoAP | UDP | 极低功耗、类 REST | 电池供电设备 |
| WebSocket | TCP | 全双工、实时 | 实时数据推送 |
二、MQTT 实战
1. MQTT 简介
MQTT(Message Queuing Telemetry Transport)是 IoT 最流行的协议,基于发布/订阅模式:
- Broker:消息服务器(如 Mosquitto、EMQ X)
- Topic:消息主题(如 `home/temperature`)
- QoS:服务质量等级(0/1/2)
- Retain:保留消息,新订阅者立即收到
2. ESP32 MQTT 客户端
// ESP32 MQTT 完整示例
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT22
#define LED_PIN 2
const char* ssid = "WiFi-SSID";
const char* password = "WiFi-Password";
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);
// MQTT 消息回调
void callback(char* topic, byte* payload, unsigned int length) {
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.printf("Topic: %s\n", topic);
Serial.printf("Message: %s\n", message.c_str());
// 处理 LED 控制
if (String(topic) == "home/led/command") {
if (message == "ON") {
digitalWrite(LED_PIN, HIGH);
client.publish("home/led/status", "ON", true);
} else if (message == "OFF") {
digitalWrite(LED_PIN, LOW);
client.publish("home/led/status", "OFF", true);
}
}
}
// 重连 MQTT
void reconnect() {
while (!client.connected()) {
String clientId = "ESP32-" + String(random(10000));
if (client.connect(clientId.c_str())) {
Serial.println("MQTT connected");
// 订阅主题
client.subscribe("home/led/command");
client.subscribe("home/config/#");
// 发布上线消息
client.publish("home/status", "online", true);
} else {
Serial.printf("MQTT failed, rc=%d\n", client.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
dht.begin();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
client.setBufferSize(512);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 每 10 秒发布传感器数据
static unsigned long lastPublish = 0;
if (millis() - lastPublish > 10000) {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (!isnan(humidity) && !isnan(temperature)) {
// JSON 格式发布
char payload[100];
snprintf(payload, sizeof(payload),
"{\"temperature\":%.1f,\"humidity\":%.1f}",
temperature, humidity);
client.publish("home/sensors", payload);
Serial.printf("Published: %s\n", payload);
}
lastPublish = millis();
}
}
三、HTTP 客户端
1. ESP32 HTTP GET/POST
// ESP32 HTTP 客户端示例
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "WiFi-SSID";
const char* password = "WiFi-Password";
// HTTP GET 请求
void httpGet() {
HTTPClient http;
http.begin("http://api.openweathermap.org/data/2.5/weather?q=Beijing&appid=YOUR_API_KEY");
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String response = http.getString();
// 解析 JSON
StaticJsonDocument<1024> doc;
deserializeJson(doc, response);
float temp = doc["main"]["temp"];
float humidity = doc["main"]["humidity"];
Serial.printf("Temperature: %.1f°C\n", temp - 273.15);
Serial.printf("Humidity: %.1f%%\n", humidity);
}
http.end();
}
// HTTP POST 请求
void httpPost(float temperature, float humidity) {
HTTPClient http;
http.begin("http://your-server.com/api/sensors");
http.addHeader("Content-Type", "application/json");
// 构建 JSON
StaticJsonDocument<256> doc;
doc["device_id"] = "esp32-001";
doc["temperature"] = temperature;
doc["humidity"] = humidity;
doc["timestamp"] = millis();
String jsonString;
serializeJson(doc, jsonString);
int httpResponseCode = http.POST(jsonString);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.printf("Response: %s\n", response.c_str());
}
http.end();
}
四、CoAP 协议
1. CoAP 简介
CoAP(Constrained Application Protocol)是专为受限设备设计的协议:
- 基于 UDP,开销极小
- 类 RESTful API(GET/POST/PUT/DELETE)
- 支持确认消息(CON)和非确认消息(NON)
- 支持 Observe 模式(类似 MQTT 订阅)
2. CoAP 客户端示例
// ESP32 CoAP 客户端
#include <coap_simple.h>
WiFiUDP udp;
CoapSimple coap(udp);
// CoAP 资源回调
void coap_callback(CoapPacket &packet, IPAddress ip, int port) {
char payload[100];
packet.payloadcopy(payload);
Serial.printf("CoAP request from %s:%d\n", ip.toString().c_str(), port);
// 返回传感器数据
float temp = dht.readTemperature();
char response[50];
snprintf(response, sizeof(response), "{\"temp\":%.1f}", temp);
coap.respond(packet, (uint8_t*)response, strlen(response));
}
void setup() {
// 注册 CoAP 资源
coap.server(coap_callback, "sensor/temperature");
coap.server(coap_callback, "sensor/humidity");
coap.server(coap_callback, "led/status");
coap.start(5683);
}
void loop() {
coap.loop();
// CoAP 定时上报(Observe 模式)
static unsigned long lastNotify = 0;
if (millis() - lastNotify > 30000) {
float temp = dht.readTemperature();
char payload[50];
snprintf(payload, sizeof(payload), "{\"temp\":%.1f}", temp);
coap.notifyObservers("sensor/temperature",
(uint8_t*)payload, strlen(payload));
lastNotify = millis();
}
}
五、WebSocket 实时通信
// ESP32 WebSocket 服务器
#include <WebServer.h>
#include <WebSocketsServer.h>
WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("WebSocket [%u] disconnected\n", num);
break;
case WStype_CONNECTED:
Serial.printf("WebSocket [%u] connected\n", num);
webSocket.sendTXT(num, "Connected to ESP32");
break;
case WStype_TEXT:
String message = String((char*)payload);
Serial.printf("WebSocket [%u]: %s\n", num, message.c_str());
// 处理命令
if (message == "get_temperature") {
float temp = dht.readTemperature();
char response[50];
snprintf(response, sizeof(response), "{\"temp\":%.1f}", temp);
webSocket.sendTXT(num, response);
}
break;
}
}
void setup() {
webSocket.begin();
webSocket.onEvent(webSocketEvent);
server.begin();
}
void loop() {
webSocket.loop();
server.handleClient();
// 每 1 秒广播传感器数据
static unsigned long lastBroadcast = 0;
if (millis() - lastBroadcast > 1000) {
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
char json[100];
snprintf(json, sizeof(json),
"{\"temp\":%.1f,\"humidity\":%.1f}", temp, humidity);
webSocket.broadcastTXT(json);
lastBroadcast = millis();
}
}
六、协议选型指南
// 协议选择决策树
需要实时双向通信?
├── 是 → WebSocket
└── 否 →
需要低功耗?
├── 是 → CoAP
└── 否 →
设备数量多?
├── 是 → MQTT(发布/订阅模式)
└── 否 → HTTP(简单直接)
// 典型应用场景
MQTT → 传感器数据上报、智能家居控制
HTTP → 固件升级、配置管理、Web API
CoAP → 电池供电设备、LPWAN 网络
WebSocket → 实时监控面板、远程调试
选择合适的网络协议是 IoT 项目成功的关键,需要根据功耗、延迟、可靠性需求综合考虑。