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

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;
}

问题原因分析

  1. ESP32端循环频率过高:app_main中的while(1)循环仅延迟1ms就重复调用recive_int_from_server,socket创建/销毁频率远超系统处理能力,大量资源未及时释放,导致文件描述符耗尽。
  2. 服务端逻辑缺陷:服务端仅接受一次连接、发送数据后就关闭socket退出,无法持续响应ESP32的多次连接请求,导致ESP32连接失败后socket资源无法正常释放。
  3. 错误处理不严谨:ESP32端在connect或recv失败时直接返回,未关闭已创建的socket,加剧资源泄漏。

解决方案

ESP32端代码修改

  1. 优化循环间隔,避免频繁创建socket
  2. 完善错误分支的socket资源释放逻辑
  3. 改为长连接模式,减少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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:57:53