You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP-Mesh根节点通过TCP Socket向电脑发送数据包失败问题排查

ESP-Mesh根节点TCP Socket发送数据失败排查

问题背景

使用ESP-IDF以C语言实现ESP-Mesh节点向电脑发送数据包:

  • 子节点调用esp_mesh_send(to参数设为null,address设为IPv4地址端口节点),根节点通过esp_mesh_recv_toDS接收数据包的流程完全正常。
  • 单独测试根节点的TCP Socket功能时一切正常,ESP已成功连接WiFi,电脑与ESP处于同一局域网。
  • 但结合Mesh组网使用时,根节点通过TCP Socket向电脑发送数据失败。

根节点Socket相关代码

void wifiTest(void){
    wifi_ap_record_t ap_info;
    esp_err_t err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK) {
        
        ESP_LOGI("wifiTest", "succesfullx conected with SSID: %s
", ap_info.ssid);
    } else {

        ESP_LOGE("wifiTest", "not connected
");
    }
}


void root_task(void ) {
    vTaskDelay(10000 / portTICK_PERIOD_MS);
    wifiTest();
    // initialization of the basic variables 
    char rx_buffer[128];
    char host_ip[] = CONFIG_SERVER_IP;

    // initialize thr server variables
    struct sockaddr_in dest_addr;
    inet_pton(AF_INET, host_ip, &dest_addr.sin_addr);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(CONFIG_SERVER_PORT);
    int addr_family = AF_INET;
    int ip_protocol = IPPROTO_IP;
    int sock = -1;

    // initialize error variables
    int sendError = 0;
    int receiveError = 0;
    int buildError = 0;
    
    // initialization finished
    ESP_LOGI(ROOT, "Socket basic variables initialized");

    while(1) {
        // create socket
        sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
        if (sock < 0) {
            ESP_LOGE(ROOT, "Unable to create socket: errno %d", errno);
            buildError++;
        }
        ESP_LOGI(ROOT, "Socket created, connecting to %s:%d", host_ip, CONFIG_SERVER_PORT);

        //connect socket to server
        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        if (err != 0) {
            ESP_LOGE(ROOT, "Socket unable to connect: errno %d", errno);
            buildError++;
        }
        ESP_LOGI(ROOT, "Successfully connected");
        buildError = 0;

        while (1) {
            //send message
            int err = send(sock, "payload", strlen("payload"), 0);
            if (err < 0) {
                ESP_LOGE(ROOT, "Error occurred during sending: errno %d", errno);
                sendError++;
                break;
            }
            sendError = 0;

            // receive message
            int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
            if (len < 0) {
                ESP_LOGE(ROOT, "recv failed: errno %d", errno);
                receiveError++;
                break;
            }else {
                rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
                ESP_LOGI(ROOT, "Received %d bytes from %s:", len, host_ip);
                ESP_LOGI(ROOT, "%s", rx_buffer);
                receiveError = 0;
            }

            // wait 1 second
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }    

        //error handling
        if(sendError>MAXERROR || receiveError>MAXERROR || buildError>MAXERROR){
            ESP_LOGE(ROOT, "root task stopped  (socket build errors: %d) (socket send errors: %d) (socket receive Errors: %d)"
            ,buildError, sendError, receiveError);
            break;
        }else{
            ESP_LOGE(ROOT, "socket build errors: %d  socket send errors: %d  socket receive Errors: %d" ,buildError, sendError, receiveError);
            ESP_LOGE(ROOT, "In 2 secunde socket buildig will tryed again");
            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }

        ESP_LOGE(ROOT, "Shutting down socket and restarting...");
        shutdown(sock, 0);
        close(sock);
    }
    #
    // close socket and release resources
    if (sock != -1) {
        ESP_LOGE(ROOT, "Shutting down socket and restarting...");
        shutdown(sock, 0);
        close(sock);
    }
    
}

排查与修复建议

1. 定位具体错误原因

代码中已打印errno,需根据数值对应分析:

  • ECONNREFUSED:电脑端未启动TCP服务,或端口监听配置错误
  • ENETUNREACH:根节点网络路由异常,Mesh环境下需确认STA连接的WiFi网络是否真的可用
  • EAGAIN/EWOULDBLOCK:资源暂时不足,需添加重试逻辑

2. 修复代码逻辑漏洞

  • Socket创建失败后的分支处理:如果socket()返回-1,后续connect()会使用无效的sockfd,需在sock < 0时直接跳转到错误处理,跳过连接步骤
  • 修正错误计数逻辑:当前buildError会在创建socket失败+连接失败时累加两次,需调整计数时机,比如仅在创建或连接单次失败时递增
  • 删除无效语法:代码中while(1)循环结束后的#属于语法错误,会导致编译失败,直接删除
  • 修正拼写错误:succesfullx→successfully、thr→the、secunde→seconds、tryed→tried,避免日志信息混淆

3. Mesh环境特殊处理

  • 分离Mesh与Socket任务:不要在Mesh接收回调中直接调用Socket发送,将Mesh收到的数据包放入消息队列,由独立的Socket任务处理,避免阻塞Mesh协议栈
  • 确认根节点网络资源:Mesh根节点同时承担Mesh路由和STA角色,可通过esp_netif配置调整网络栈资源分配,避免Mesh占用过多资源导致Socket异常
  • 验证目标IP正确性:确保CONFIG_SERVER_IP是电脑在当前局域网的真实IPv4地址,而非Mesh内部节点地址

4. 添加网络连通性验证

在wifiTest后添加ping测试,确认根节点到电脑的网络可达性:

// 示例:ping目标电脑IP
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
ping_config.target_addr.type = ESP_PING_IPADDR_TYPE_V4;
inet_pton(AF_INET, host_ip, &ping_config.target_addr.u.ipv4);
ping_config.count = 3;
esp_ping_handle_t ping_handle = NULL;
esp_ping_new_session(&ping_config, NULL, NULL, &ping_handle);
esp_ping_start(ping_handle);
vTaskDelay(3000 / portTICK_PERIOD_MS);
esp_ping_stop(ping_handle);
esp_ping_delete_session(ping_handle);

内容的提问来源于stack exchange,提问作者Loewion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:04:55