十一、【ESP32开发全栈指南: TCP通信服务端】

一、TCP与UDP协议对比

1.1 基本特性比较

TCP(传输控制协议)和UDP(用户数据报协议)是两种最常用的传输层协议,它们在ESP32网络编程中都有广泛应用:

  1. 「连接方式」

    • TCP是面向连接的协议,通信前需要先建立连接(三次握手)

    • UDP是无连接的协议,直接发送数据包

  2. 「可靠性」

    • TCP提供可靠传输,保证数据无差错、不丢失、不重复且按序到达

    • UDP提供尽力而为的交付,不保证可靠性

  3. 「实时性」

    • UDP具有更好的实时性,传输效率更高

    • TCP由于重传机制和流量控制,实时性相对较低

  4. 「连接模式」

    • TCP仅支持点到点通信

    • UDP支持一对一、一对多、多对多等多种通信模式

  5. 「资源消耗」

    • TCP需要维护连接状态,系统资源消耗较大

    • UDP实现简单,资源消耗较少

1.2 ESP32中的协议栈支持

ESP-IDF使用开源的lwIP轻量级TCP/IP协议栈,并对原始版本进行了优化和扩展:

  • 支持BSD Socket API标准接口

  • 支持Netconn API(但官方不推荐使用)

  • 针对嵌入式系统进行了内存优化

  • 支持IPv4和IPv6双协议栈

二、TCP服务器核心API

2.1 关键Socket函数

ESP32通过BSD Socket接口实现TCP通信,主要API包括:

  1. 「socket()」 – 创建通信端点

  2. 「bind()」 – 绑定本地地址和端口

  3. 「listen()」 – 开始监听连接请求

  4. 「accept()」 – 接受客户端连接

  5. 「recv()/send()」 – 接收/发送数据

  6. 「shutdown()/close()」 – 关闭连接

2.2 特殊功能支持

除了标准BSD Socket API外,ESP32还支持:

  • 「fcntl()」 – 控制socket属性

  • 「ioctl()」 – I/O设备控制

  • 「select()」 – I/O多路复用

  • 「poll()」 – (通过select实现)

三、TCP服务器实现流程

3.1 完整实现步骤

  1. 「创建socket」

    int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if(listen_sock < 0) {
        ESP_LOGE(TAG, "创建socket失败: errno %d", errno);
    }
  2. 「配置服务器地址」

    struct sockaddr_in dest_addr;
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    dest_addr.sin_port = htons(TCP_PORT);
  3. 「绑定地址」

    int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if(err != 0) {
        ESP_LOGE(TAG, "绑定失败: errno %d", errno);
        close(listen_sock);
    }
  4. 「开始监听」

    err = listen(listen_sock, 1);  // 参数1表示最大等待连接数
    if(err != 0) {
        ESP_LOGE(TAG, "监听失败: errno %d", errno);
        close(listen_sock);
    }
  5. 「接受连接」

    struct sockaddr_in6 source_addr;
    uint addr_len = sizeof(source_addr);
    int connect_sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
  6. 「数据收发」

    // 接收数据
    len = recv(connect_sock, rx_buffer, sizeof(rx_buffer), 0);

    // 发送数据
    send(connect_sock, tx_buffer, len, 0);

3.2 连接管理注意事项

  • 每个accept()会创建一个新的socket专门用于该连接

  • 原始监听socket继续用于接受新连接

  • 需要合理管理连接资源,及时关闭不再使用的socket

  • 对于多客户端场景,建议使用多任务或select/poll管理

四、Wi-Fi模式配置

4.1 Station模式(连接路由器)

// 使用示例提供的辅助函数连接Wi-Fi
ESP_ERROR_CHECK(example_connect());

4.2 AP模式(创建热点)

void wifi_init_softap(void) {
    // 初始化网络接口
    esp_netif_create_default_wifi_ap();
    
    // 配置AP参数
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = "ESP32_AP",
            .password = "12345678",
            .max_connection = 4,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };
    
    // 启动AP
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}

五、完整示例代码分析

5.1 主任务流程

void app_main(void)
{
    // 初始化NVS存储
    ESP_ERROR_CHECK(nvs_flash_init());
    
    // 初始化网络
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    
    // 连接Wi-Fi(Station模式)或创建AP
    // ESP_ERROR_CHECK(example_connect());  // Station模式
    wifi_init_softap();                   // AP模式
    
    // 创建TCP服务器任务
    xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET, 5, NULL);
}

5.2 TCP服务器任务

static void tcp_server_task(void *pvParameters)
{
    // 1. 创建socket
    int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    
    // 2. 绑定地址
    struct sockaddr_in dest_addr;
    // ... 配置地址 ...
    bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    
    // 3. 开始监听
    listen(listen_sock, 1);
    
    while(1) {
        // 4. 接受新连接
        int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
        
        // 5. 处理连接
        do_retransmit(sock);
        
        // 6. 关闭连接
        close(sock);
    }
}

5.3 数据传输处理

static void do_retransmit(const int sock)
{
    char rx_buffer[128];
    
    while(1) {
        // 接收数据
        int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
        
        if(len > 0) {
            // 处理接收到的数据
            process_data(rx_buffer, len);
            
            // 发送响应
            send(sock, response, response_len, 0);
        } elseif(len == 0) {
            // 连接关闭
            break;
        } else {
            // 错误处理
            handle_error();
        }
    }
}

六、性能优化与调试

6.1 常见问题解决

  1. 「连接失败」

    • 检查Wi-Fi连接状态

    • 确认端口未被占用

    • 检查防火墙设置

  2. 「数据传输不稳定」

    • 增加接收缓冲区大小

    • 实现重传机制

    • 优化任务优先级

  3. 「内存不足」

    • 调整lwIP内存池大小

    • 及时释放socket资源

    • 使用内存优化配置

6.2 配置选项

通过menuconfig配置关键参数:

idf.py menuconfig

重要配置项:

  • Component config → LWIP → 内存配置

  • Example Connection Configuration → Wi-Fi/以太网设置

  • Example Configuration → 服务器端口号

七、应用场景扩展

7.1 物联网控制

  • 实现远程设备控制

  • 状态监控与数据采集

  • 固件OTA升级

7.2 工业应用

  • 设备间可靠通信

  • 实时数据传输

  • 远程诊断与维护

7.3 智能家居

  • 家庭设备组网

  • 集中控制与管理

  • 安全通信保障

通过合理设计和优化,ESP32 TCP服务器可以满足各种物联网应用的通信需求,提供稳定可靠的数据传输服务。

发表评论