首页 > 解决方案 > esp32 idf 多套接字服务器

问题描述

这是我的第一篇文章,所以如果可以提供帮助,请远程请求任何东西,但我没有提供。

我的应用程序需要从 Master 一次打开多个套接字,然后从机连接到 WiFi,然后再连接到套接字

问题是:我必须使其“防弹”以防止不断地从从站重新连接,我收到 Accept error: E (23817) TCP SOCKET: accept error: -1 Too many open files in system 当我第 5 次重新连接客户端时出现,当在 menuconfig 中打开套接字的最大数量 = 5 时,

当客户端在 1 秒内没有发送任何内容时,我断开客户端与服务器的连接 -> 然后我假设他们得到了 DC-d。我用 close() 程序来做。

void closeOvertimedTask(void * ignore)
{
    while(1)
    {
        for(int i = 0; i < openedSockets;)
        {
            if(needsRestart[i] == 1)
            {
                ESP_LOGI("RESTARTING", " task#%d",i);
                //lwip_close_r(clientSock[i]);

                //closesocket(clientSock[i]);

                //ESP_LOGI("closing result", "%d", close(clientSock[i]));
                stopSocketHandler(i);
                needsRestart[i] = 0;
                //if(isSocketOpened[i])
                {

                }

                ESP_LOGI("close", "%d", lwip_close_r(clientSock[i]));
                isSocketOpened[i] = 0;

                xTaskCreate( handleNthSocket, "TCP_HANDLER", 10*1024, &(sockNums[i]) , tskIDLE_PRIORITY, &socketHandlerHandle[i]);
                configASSERT(socketHandlerHandle[i]);
                needsRestart[i] = 0;
            }

            if(isSocketOpened[i])
            {
                int diff = ((int)((uint64_t)esp_timer_get_time()) - lastWDT[i]) - 2*TCPWDT;

                if(diff > 0)
                {
                    if(isSocketOpened[i])
                    {
                        ESP_LOGI("I FOUND OUT HE DC-d","");
                        //closesocket(clientSock[i]);
                    }
                    ESP_LOGI("close", "%d", close(clientSock[i]));

                    stopSocketHandler(i);
                    isSocketOpened[i] = 0;

                    xTaskCreate( handleNthSocket, "TCP_HANDLER", 10*1024, &(sockNums[i]) , tskIDLE_PRIORITY, &socketHandlerHandle[i]);
                    configASSERT(socketHandlerHandle[i]);
                }
            }

        }
    }
}

对于每个套接字,我运行 1 个任务,该任务应该从该套接字接收并进一步采取行动。

对于他们所有人,我还有另一个任务检查上次消息到达的时间并在超过时间时重新启动任务(这是 2 秒)

我需要在最终版本中打开大约 16 个套接字,因此在从站重新启动整个连接后,没有空间让套接字仍然关闭

  1. 如何正确关闭任务并在其中运行 recv() 过程以正确关闭 Socket。
  2. 如果 WiFi 没有实现 STA DC-d,有没有办法从服务器端读取套接字已关闭
  3. 这是关于来自 tcp 堆栈的 TIME_WAIT 吗?

套接字读取代码:

void handleNthSocket(void * param) // 0 <= whichSocket < openedSockets 
{
    int whichSocket =  *((int *) param);

    ESP_LOGI("TCP SOCKET", "%s     #%d", getSpaces(whichSocket), whichSocket);
    struct sockaddr_in clientAddress;

    while (1) 
    {
        if(needsRestart [whichSocket] == 0)
        {
            socklen_t clientAddressLength = sizeof(clientAddress);
            clientSock[whichSocket] = accept(sock[whichSocket], (struct sockaddr *)&clientAddress, &clientAddressLength);
            if (clientSock[whichSocket] < 0) 
            {
                ESP_LOGE("TCP SOCKET", "accept error: %d %s", clientSock[whichSocket], strerror(errno));  //HERE IT FLIPS
                //E (232189) TCP SOCKET: accept error: -1 Too many open files in system

                isSocketOpened[whichSocket] = 0;
                needsRestart[whichSocket] = 1;
                continue;
            }
            //isSocketOpened[whichSocket] = 1;
            // We now have a new client ...

            int total = 1000;

            char dataNP[1000];
            char *data;
            data = &dataNP[0];

            for(int z = 0; z < total; z++)
            {
                dataNP[z] = 0;
            } 
            ESP_LOGI("TCP SOCKET", "%snew client",getSpaces(whichSocket));
            ESP_LOGI("          ", "%s#%d connected",getSpaces(whichSocket), whichSocket);
            lastWDT[whichSocket] = (uint64_t)esp_timer_get_time() + 1000000;
            isSocketOpened[whichSocket] = 1;
            // Loop reading data.


            while(isSocketOpened[whichSocket]) 
            {
                /*
                if (sizeRead < 0) 
                {
                    ESP_LOGE(tag, "recv: %d %s", sizeRead, strerror(errno));                
                    goto END;
                }

                if (sizeRead == 0) 
                {
                    break;
                }
                sizeUsed += sizeRead;
                */

                ssize_t sizeRead = recv(clientSock[whichSocket], data, total, 0);
                /*for (int k = 0; k < sizeRead; k++)
                {
                    if(*(data+k) == '\n')
                    {
                        ESP_LOGI("TCP DATA  ", "%sthere was enter", getSpaces(whichSocket));
                        //ESP_LOGI("TIME      ", "%d", (int)esp_timer_get_time());
                    }
                    //ESP_LOGI("last wdt", "%d", (int)lastWDT[whichSocket]);

                }*/


                lastWDT[whichSocket] = (uint64_t)esp_timer_get_time();
                int diff = ((int)((uint64_t)esp_timer_get_time()) - lastWDT[whichSocket]) - 2*TCPWDT;
                ESP_LOGI("last wdt", "%d, data = %s", (int)lastWDT[whichSocket], data);

                if(diff > 0)
                {
                    ESP_LOGI("last wdt", "too long - %d", diff);
                    isSocketOpened[whichSocket] = 0;
                }

                if (sizeRead < 0)
                {
                    isSocketOpened[whichSocket] = 0;
                }


                //TODO: all RX from slave routine
                for(int k = 0; k < sizeRead; k++)
                {
                    *(data+k) = 0;
                }



    //          ESP_LOGI("lol data", "clientSock[whichSocket]=%d, 
                /*if(sizeRead > -1)
                {
                    ESP_LOGI("TCP DATA: ", "%c", *(data + sizeRead-1));
                }
                else
                {
                    ESP_LOGI("TCP DC    ", "");
                    goto END;               
                }*/     



            }
            if(isSocketOpened[whichSocket])
            {
                ESP_LOGI("closing result", "%d", close(clientSock[whichSocket]));
            }
        }       
    }
}

标签: csocketsserveresp32

解决方案


I don't see you closing your sockets anywhere?

Sockets, no matter the platform, is usually a limited resource, and a resource that will be reused. If you don't close the sockets then the system will think that you still use then, and can't reuse those sockets for new connections (and on POSIX systems even opening files will be affected).

So close connections immediately when they are not needed any more.

Usually this is done by checking what recv and send returns: If they return a value less than zero an error occured and in most cases it's a non-recoverable errors, so connection should be closed. Even if it is a recoverable error, it's easier to close the connection and let the client reconnect.

For recv there's also the special case when it returns zero. That means the other end has closed the connection. That of course you need to close your end as well.


推荐阅读