ESP32 TCP客户端创建失败:系统打开文件过多问题求助
问题解决:ESP32 TCP Socket创建报错及功能实现
需求与现状
- 需求:ESP32通过TCP Socket收到数据1时,将GPIO12引脚置高电平
- 前期测试:两台电脑的TCP客户端/服务端功能正常;ESP32可正常连接WiFi获取IP和MAC地址
- 当前问题:执行socket创建代码时,串口输出报错:
socket creation: Too many open files in system
报错代码片段:
if((network_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket creation"); return 0; }
问题原因分析
- ESP32端循环频率过高:
app_main中的while(1)循环仅延迟1ms就重复调用recive_int_from_server,socket创建/销毁频率远超系统处理能力,大量资源未及时释放,导致文件描述符耗尽。 - 服务端逻辑缺陷:服务端仅接受一次连接、发送数据后就关闭socket退出,无法持续响应ESP32的多次连接请求,导致ESP32连接失败后socket资源无法正常释放。
- 错误处理不严谨:ESP32端在
connect或recv失败时直接返回,未关闭已创建的socket,加剧资源泄漏。
解决方案
ESP32端代码修改
- 优化循环间隔,避免频繁创建socket
- 完善错误分支的socket资源释放逻辑
- 改为长连接模式,减少socket创建销毁次数
修改后的核心代码:
#include <stdio.h> #include <string.h> #include "freertos/FreeRTOS.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_log.h" #include "esp_event.h" #include "nvs_flash.h" #include "lwip/err.h" #include "lwip/sys.h" #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> #include <errno.h> #include "driver/gpio.h" #include "freertos/task.h" #define LED 12 const char *TAG = "CONNECT TO TCP"; const char *ssid = "你的WiFi名称"; const char *pass = "你的WiFi密码"; int retry_num=0; int network_socket = -1; static void wifi_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id,void *event_data){ if(event_id == WIFI_EVENT_STA_START) printf("WIFI CONNECTING....\n"); else if (event_id == WIFI_EVENT_STA_CONNECTED) printf("WiFi CONNECTED\n"); else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { printf("WiFi lost connection\n"); if(retry_num<5){esp_wifi_connect();retry_num++;printf("Retrying to Connect...\n");} } else if (event_id == IP_EVENT_STA_GOT_IP) printf("Wifi got IP...\n\n"); } void wifi_connection() { esp_netif_init(); esp_event_loop_create_default(); esp_netif_create_default_wifi_sta(); wifi_init_config_t wifi_initiation = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&wifi_initiation); esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL); esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL); wifi_config_t wifi_configuration = { .sta = {.ssid = "", .password = ""} }; strcpy((char*)wifi_configuration.sta.ssid, ssid); strcpy((char*)wifi_configuration.sta.password, pass); esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_configuration); esp_wifi_start(); esp_wifi_set_mode(WIFI_MODE_STA); esp_wifi_connect(); printf( "wifi_init_softap finished. SSID:%s password:%s\n",ssid,pass); } int connect_to_server(void) { if (network_socket != -1) { close(network_socket); } network_socket = socket(AF_INET, SOCK_STREAM, 0); if (network_socket == -1) { perror("socket creation"); return -1; } struct sockaddr_in server_address; server_address.sin_family = AF_INET; server_address.sin_port = htons(5067); server_address.sin_addr.s_addr = inet_addr("10.0.1.175"); if (connect(network_socket, (struct sockaddr *)&server_address, sizeof(server_address)) != 0) { perror("socket connection"); close(network_socket); network_socket = -1; return -1; } return 0; } int recive_int_from_server(void) { if (network_socket == -1) { if (connect_to_server() != 0) { return -1; } } char server_response[250] = {0}; ssize_t recv_len = recv(network_socket, server_response, sizeof(server_response)-1, 0); if (recv_len <= 0) { perror("recv failed"); close(network_socket); network_socket = -1; return -1; } int resp = atoi(server_response); ESP_LOGI(TAG,"%i", resp); return resp; } void app_main(void) { char *MSG = pcTaskGetName(NULL); nvs_flash_init(); gpio_set_direction(LED, GPIO_MODE_OUTPUT); wifi_connection(); while(1) { int msg = recive_int_from_server(); ESP_LOGI(MSG, "%i", msg); if(msg == 1) gpio_set_level(LED, 1); else if(msg == 0) gpio_set_level(LED, 0); vTaskDelay(pdMS_TO_TICKS(1000)); // 修改为1秒循环间隔 } }
服务端代码修改
修改为循环接受连接,持续响应客户端请求:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> int main () { char server_message[250] = "1 \n\r"; int server_socket = socket(AF_INET, SOCK_STREAM, 0); if(server_socket == -1) { perror("socket"); return 0; } struct sockaddr_in server_addres; server_addres.sin_family = AF_INET; server_addres.sin_port = htons(5067); server_addres.sin_addr.s_addr = INADDR_ANY; if(bind(server_socket, (struct sockaddr *) &server_addres, sizeof(server_addres)) != 0) { perror("bind"); close(server_socket); return 0; } if(listen(server_socket, 5) !=0) { perror("listen"); close(server_socket); return 0; } printf("Server listening on port 5067...\n"); while(1) { int client_socket = accept(server_socket, NULL, NULL); if(client_socket == -1) { perror("accept"); continue; } printf("Client connected\n"); if(send(client_socket, server_message, strlen(server_message), 0) == -1) { perror("send"); } close(client_socket); } close(server_socket); return 0; }
额外注意事项
- 确保ESP32代码中
ssid和pass字段已正确填写WiFi账号密码 - 服务端运行时,可通过
netstat -tulpn | grep 5067检查端口是否被占用 - ESP32的GPIO12引脚部分模块中与Flash电源相关,需注意硬件兼容性
内容的提问来源于stack exchange,提问作者Tomas barta
相关产品推荐
相关产品推荐

