一、TCP协议核心特性回顾
TCP与UDP关键差异
|
特性 |
TCP |
UDP |
|---|---|---|
| 「连接方式」 |
面向连接 (三次握手) |
无连接 |
| 「可靠性」 |
可靠传输 (重传/排序/校验) |
尽力交付 |
| 「数据顺序」 |
保证数据按序到达 |
不保证顺序 |
| 「流控制」 |
滑动窗口机制 |
无流控制 |
| 「传输效率」 |
协议开销大 |
头部开销小 |
| 「适用场景」 |
文件传输、网页浏览 |
实时音视频、广播通信 |
❝
📌 「ESP32应用场景」:OTA固件升级(TCP)、传感器数据上报(UDP)、远程控制(TCP)
❞
二、ESP32网络架构
-
「lwIP轻量级TCP/IP栈」
-
ESP-IDF定制版本: esp-lwip -
支持全功能BSD Socket API -
默认启用TCP/IP协议栈 -
「核心组件」
-
「ESP-NETIF」:网络接口抽象层 -
「事件循环」:处理网络事件 -
「协议栈配置」:通过menuconfig调整
三、TCP客户端开发流程
3.1 工作流程
3.2 代码实现详解
// 创建TCP客户端
void tcp_client_task(void *pvParameters) {
// 1. 创建套接字
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock < 0) {
ESP_LOGE(TAG, "创建套接字失败: errno %d", errno);
vTaskDelete(NULL);
}
// 2. 配置服务器地址
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(CONFIG_TARGET_PORT),
.sin_addr.s_addr = inet_addr(CONFIG_TARGET_IP)
};
// 3. 连接服务器
int retry_count = 0;
while (connect(sock, (struct sockaddr *)&server_addr,
sizeof(server_addr)) != 0)
{
if (++retry_count > 5) {
ESP_LOGE(TAG, "连接失败, 错误码: %d", errno);
close(sock);
vTaskDelete(NULL);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "成功连接到服务器 %s:%d",
CONFIG_TARGET_IP, CONFIG_TARGET_PORT);
// 4. 数据交换循环
char rx_buffer[128];
while (1) {
// 发送数据
const char *payload = "ESP32心跳";
if (send(sock, payload, strlen(payload), 0) < 0) {
ESP_LOGE(TAG, "发送失败: %d", errno);
break;
}
// 接收数据 (带超时设置)
struct timeval tv = { .tv_sec = 10 };
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
int len = recv(sock, rx_buffer, sizeof(rx_buffer)-1, 0);
if (len > 0) {
rx_buffer[len] = '\0';
ESP_LOGI(TAG, "收到 %d 字节: %s", len, rx_buffer);
} else if (len == 0) {
ESP_LOGW(TAG, "连接被服务器关闭");
break;
} else {
ESP_LOGE(TAG, "接收错误: %d", errno);
break;
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
// 5. 清理资源
shutdown(sock, 0);
close(sock);
vTaskDelete(NULL);
}
3.3 关键函数解析
-
「socket()」
-
AF_INET:IPv4协议族 -
SOCK_STREAM:流式套接字(TCP) -
返回值:套接字描述符(负数为错误) -
「connect()」
-
阻塞式连接(默认) -
可设置非阻塞模式: fcntl(sock, F_SETFL, O_NONBLOCK); -
「send()/recv()」
-
面向连接的数据传输 -
注意处理部分发送/接收情况
四、WiFi连接模式
4.1 Station模式(直连路由器)
void wifi_init_sta() {
// 标准初始化流程
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 配置WiFi参数
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD
}
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_connect());
}
4.2 SmartConfig配网模式
「实现关键点」:
// SmartConfig事件处理
static void sc_event_handler(void* arg, esp_event_base_t base,
int32_t id, void* data) {
if (id == SC_EVENT_GOT_SSID_PSWD) {
// 提取配置信息
smartconfig_event_got_ssid_pswd_t *evt = data;
// 配置WiFi
wifi_config_t wifi_config = {0};
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(evt->ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(evt->password));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_connect());
}
else if (id == SC_EVENT_SEND_ACK_DONE) {
// 启动TCP客户端任务
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}
}
五、高级功能与优化
5.1 连接保活机制
// 启用TCP Keepalive
int keepalive_enable = 1;
int keepalive_idle = 30; // 30秒无活动发送探测
int keepalive_interval = 5; // 探测间隔
int keepalive_count = 3; // 最大探测次数
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive_enable, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive_interval, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_count, sizeof(int));
5.2 错误处理策略
-
「连接失败」:
int delay_ms = 1000;
while (connect() != 0) {
vTaskDelay(delay_ms / portTICK_PERIOD_MS);
delay_ms *= 2; // 指数退避
if (delay_ms > 30000) delay_ms = 30000;
} -
检查网络状态 -
实现指数退避重连 -
「传输中断」:
-
检测errno值 -
重建连接恢复传输
5.3 性能优化技巧
-
「增大发送缓冲区」:
int send_buf_size = 8192;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &send_buf_size, sizeof(send_buf_size)); -
「使用Nagle算法」:
int nagle_disable = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &nagle_disable, sizeof(nagle_disable));
六、实战应用场景
6.1 固件OTA升级
6.2 远程设备控制
+----------+ +------------+ +----------+
| 手机APP | ---> | 云服务器 | ---> | ESP32设备|
| (控制指令)| | (TCP中转) | | (执行动作)|
+----------+ +------------+ +----------+
6.3 数据同步系统
void sync_data_to_server() {
// 1. 建立TCP连接
// 2. 发送本地存储的数据
// 3. 接收服务器确认
// 4. 标记已同步数据
// 5. 保持长连接接收新指令
}
七、调试与问题排查
-
「常见错误代码」:
-
ECONNREFUSED(111):服务器拒绝连接 -
ETIMEDOUT(110):连接超时 -
ENOBUFS(105):缓冲区不足 -
ECONNRESET(104):连接被重置 -
「诊断工具」:
-
Wireshark抓包分析 -
ESP-IDF内置网络调试工具: idf.py monitor -
LwIP统计信息: #include "lwip/stats.h"
stats_display(); -
「连接问题检查清单」:
-
WiFi是否连接成功 -
服务器IP和端口是否正确 -
防火墙是否放行端口 -
服务器应用是否运行
❝
完整示例代码:ESP-IDF TCP客户端示例
❞
通过本指南,您将掌握ESP32 TCP客户端开发的完整流程,从基础连接到高级优化,满足各类物联网应用的通信需求。