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
相关产品推荐
相关产品推荐

