This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

EK-TM4C1294XL: TCP Client sockets creation fails after 10 times socket() calls

Part Number: EK-TM4C1294XL

Here is the scenario where I have TM4C1294 Eval board is acting as a TCP Client. I have multiple TCP Servers connected with the help of the Ethernet Socket.  (Block Diagram below)

The TCP Clent will poll data from every server in a sequential pattern. Here the firmware for the TCP client will be in a loop and it creates a socket, connects to the server issues commands and gets the responses and disconnects. Then connects to another server and this continues.

I could iterate till 10 connections after that I am unable to create sockets. socket() returns error. I know something is missed but could not figure it out. Something tin the creation of the sockets and freeing up of the sockets have to be done as this can iterate over many numbers of times.

Here is the code as below, (tcpWorker function). The code is a modified version of the sample TCP Client Echo code available.

Void tcpWorker(UArg arg0, UArg arg1)
{
    int  clientfd = (int)arg0;
    int  bytesRcvd;
    int  bytesSent;

    int count = 0;
    int countCmd=0;

    int status;
    struct sockaddr_in servAddr;
    Error_Block        eb;

    System_printf("tcpWorker: start clientfd = 0x%x\n", clientfd);
    System_flush();

    // Creating a socket
    clientfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (clientfd < 0) {
        System_printf("tcpHandler: socket failed\n");
        close(clientfd);
    }
    ///

    //////////////////// Connecting and fetching data from all the servers /////////////////////////
    //while(countCmd < MAX_CMD)
    //while(countCmd < 20)
    while(true)
    {
     if(enablePool)
     {
      System_printf("Reading IP Adddress %d ... \n", countCmd);
      System_flush();

      //////// Read the CMD Ring Buffer //////////
      readCmd();
      ////////////

      // Condition-1 ; initConnect --> True , statusCmpIP --> False
      if(initConnect && !(statusCmpIP) )
      {
          //// For DEBUG ///
          System_printf("*** CONDITION-1 ***\n");
          System_flush();
          /////////////////

          ////// Reading Server IP Address Data ///////
//          memset((char *) &servAddr, 0, sizeof(servAddr));
          servAddr.sin_family = AF_INET;
          servAddr.sin_port = htons(PORT_NUM);

          servAddr.sin_addr.s_addr = inet_addr(bufferStringIP);
          //////////////////////////////////////////////////////////

          // Connecting to a server
          status = connect(clientfd, (struct sockaddr *) &servAddr, sizeof(servAddr));

          if (status < 0) {
               System_printf("Error: client connect failed. (%d)\n",fdError());
               System_flush();

               close(clientfd);
          }

          //Reset the initialConnect Flag to False (0)
          initConnect = false;
      }
      else if(!(initConnect) && !(statusCmpIP)) {
          ///// For DEBUG //////
          System_printf("*** CONDITION-2 ***\n");
          System_flush();
          /////////////////////

          //Close socket
          close(clientfd);

          // Creating a socket
          clientfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
          if (clientfd < 0) {
              System_printf("tcpHandler: socket failed\n");
              close(clientfd);
          }
          ///

          ////// Reading Server IP Address Data ///////
//          memset((char *) &servAddr, 0, sizeof(servAddr));
          servAddr.sin_family = AF_INET;
          //servAddr.sin_port = htons(ipT[numIPCount].server_port);
          servAddr.sin_port = htons(PORT_NUM);
          servAddr.sin_addr.s_addr = inet_addr(bufferStringIP);
          //////////////////////////////////////////////////////////

          // DEBUG MSG : Connecting to a server
          System_printf("Connecting to %s\n",bufferStringIP);
          System_flush();
          /////

          status = connect(clientfd, (struct sockaddr *) &servAddr, sizeof(servAddr));

          if (status < 0) {
               System_printf("Error: client connect failed. (%d)\n",fdError());
               System_flush();

               close(clientfd);
          }
      }
      else if(!(initConnect) && statusCmpIP ) {
          //Dont have to do anything except send
          System_printf("*** CONDITION-3 ***\n");
          System_flush();
      }
      else {
          // Dont do anything
      }

      ///// Send a message to the server /////////
      //send(clientfd, msg, strlen(msg), 0);
      //send(clientfd, bufferModTx, strlen(bufferModTx),0);

      ////  DEBUG :    Reading the clientfd
      System_printf("********** CLIENT ID : %d **********\n", clientfd);
      System_flush();

      // Send First read Command
      send(clientfd, bufferModTx,MODCMD_SIZE,0);
      //sendto(clientfd, bufferModTx,MODCMD_SIZE,0,(struct sockaddr *) &servAddr, sizeof(servAddr));

      // Init the Error_Block //
      Error_init(&eb);
      ////////////////////////

      ///// Reading the response received /////
      //while ((bytesRcvd = recv(clientfd, buffer, TCPPACKETSIZE, 0)) > 0)
      //while ((bytesRcvd = recvfrom(clientfd, buffer, RESP_SIZE, 0,(struct sockaddr *) &servAddr,&addrlen)) > 0)
      while ((bytesRcvd = recv(clientfd, buffer, RESP_SIZE, 0)) > 0)
      {

        ////// DEBUG MSG //////
        System_printf("Received data : %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \r\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4],buffer[5],buffer[6],buffer[7],buffer[8],buffer[9],buffer[10]);
        System_flush();

        // Pushing the response received to the RNG BUFFER for being sent to the CO-PRO UART
////        RingBufWrite(&psRingBuf, buffer, RESP_SIZE);

        // Issue new commands

        // Read from the CMD RNG BUFFER

        // Check if the IP Address is same if not disconnect and establish new connection

        // Send the MODBUS COMMAND
        send(clientfd, bufferModTx,MODCMD_SIZE,0);
        //sendto(clientfd, bufferModTx,MODCMD_SIZE,0,(struct sockaddr *) &servAddr, sizeof(servAddr));
        ////////////

        /*
        if (bytesSent < 0 || bytesSent != bytesRcvd)
        {
            System_printf("Error: send failed.\n");
            System_flush();

            break;
        }
        */

        count = count + 1;
        if(count > 10)
        {
            break;
        }
      }

      //close(clientfd);     //  This is now taken care in the routine above

      countCmd = countCmd+1;
      count = 0;
     }   // Close for if condition of the enablePool
    }    // Close one iteration of the IP Table
    //////////////////////////

}

  • This is the sequence of operations here
    1. Create Socket.
    2. Connect to IP Address - 192.168.0.100
    3. Send data/Receive responses
    4. Close
    5. Connect to IP Address - 192.168.0.101
    6. Send Data/Receive Responses
    7. Close
    8. ----- Continues forever in a loop---

  • Hi,

      Not sure what is going on...

      Is tcpWorker a task created by another task (e.g. tcpHandler)? Since I don't know where tcpWorker task is created from, I need to ask if tcpWorker task is created repeatedly? Also whichever function that created the tcpWorker task, does it also open the socket too?

      I see you open a socket at line 18. If initConnect is true then you try to connect to the server without closing the socket at the end. However, when initConnect is false, you first close the socket and then open the socket again but without closing the socket again. You seem to have more sockets opened than sockets closed. You must check that you don't keep adding sockets N times but closing the sockets less than N number of times. In another word, You can not let outstanding sockets keep on piling up. This can result in memory overflow. 

  • Hi Charles,

    To Simplify things further. I create a test code that just has the tcpHandler function removing the tcpWorker that was shared last time.

    This simplified the overall scenario, so here it would open a socket, connect, send "Hello" message to the server which echos the message back. The client waits till it receives the message and then it would close the socket and iterate over in a while loop.

    After the 12th iterations, the socket() creation returns -1 and we hit a hard fault.

    Void tcpHandler(UArg arg0, UArg arg1)
    {
        int                status;
        int                clientfd;
        struct sockaddr_in servAddr;
        Error_Block        eb;
        char msg[] = "Hello\n";
        int count =0;
    
        int  bytesRcvd;
        //char buffer[TCPPACKETSIZE];
        char buffer[11];
    
        while(1)
        {
         count = count+1;
         System_printf("Count : %d\r\n",count);
        /*
         * Create a TCP stream socket.
         */
        clientfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (clientfd < 0) {
            System_printf("tcpHandler: socket failed\n");
            close(clientfd);
        }
    
        /*
         * Setup the Server IP address and port
         */
        memset((char *) &servAddr, 0, sizeof(servAddr));
        servAddr.sin_family = AF_INET;
        servAddr.sin_port = htons(SERVER_PORT);
        servAddr.sin_addr.s_addr = inet_addr(SERVER_IPADDR);
    
        /*
         * Connect to the server
         */
        status = connect(clientfd, (struct sockaddr *) &servAddr, sizeof(servAddr));
    
        if (status < 0) {
            System_printf("Error: client connect failed. (%d)\n",fdError());
            close(clientfd);
        }
    
        /*
         * Send a greetings message to the server
         */
        send(clientfd, msg, strlen(msg), 0);
    
        /* Init the Error_Block */
        Error_init(&eb);
    
        while ((bytesRcvd = recv(clientfd, buffer, TCPPACKETSIZE, 0)) > 0)
        {
            System_printf("RECEIVED %s\r\n",buffer);
            System_flush();
            //////
            break;
        }
    
    
        System_printf("tcpWorker stop clientfd = 0x%x\n", clientfd);
        close(clientfd);
    
        Task_sleep(1000);
       }
    }

    So effective we are opening and closing the created socket in every iteration. Is there a kind of memory allocated to the socket being created and we are not clearing it somehow even though we do a close socket here? What is that function that frees up memory for the created sockets? I could not figure it out from the TI-NDK documents.

    Thanks & Regards,

    Punith

  • Hi,

      Not really an expert on NDK as to why it will stop after 11 connection/close. It is possible there is some memory leak somewhere. I found this post that has similar issue compared to yours. Would you please take a look at this post and the suggested solution provided. 

    https://e2e.ti.com/support/legacy_forums/embedded/tirtos/f/ti-rtos-forum-read-only-archived/550413/possible-memory-leak-when-attempting-to-connect-to-a-tcp-server-with-ndk

  • Thank you very much, Charles. 

    After going through the link you shared, I found the exact issue. It was not directly a memory issue but the socket close did not immediately close the socket but it would keep it open for some time and due to the iterative nature of the socket creation it created an issue.

    I used the setSocketOpt as described in the link posted by you.

    linger_opts.l_onoff = 1;
    linger_opts.l_linger = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &linger_opts, sizeof(linger_opts));

    This is my updated snippet of the code now.

    Void tcpHandler(UArg arg0, UArg arg1)
    {
        int                status;
        int                clientfd;
        struct sockaddr_in servAddr;
        Error_Block        eb;
        char msg[] = "Hello\n";
        int count =0;
    
        int  bytesRcvd;
        //char buffer[TCPPACKETSIZE];
        char buffer[11];
    
        struct linger lingerOpts;
    
        int i = sizeof(struct linger);
        lingerOpts.l_onoff = 1;
        lingerOpts.l_linger = 0;
    
        while(1)
        {
         count = count+1;
         System_printf("Count : %d\r\n",count);
        /*
         * Create a TCP stream socket.
         */
        fdOpenSession(TaskSelf());
    
        clientfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (clientfd < 0) {
            System_printf("tcpHandler: socket failed\n");
            close(clientfd);
        }
    
        System_printf("tcpWorker start clientfd = 0x%x\n", clientfd);
        /*
         * Setup the Server IP address and port
         */
        memset((char *) &servAddr, 0, sizeof(servAddr));
        servAddr.sin_family = AF_INET;
        servAddr.sin_port = htons(SERVER_PORT);
        servAddr.sin_addr.s_addr = inet_addr(SERVER_IPADDR);
    
        /////
        setsockopt(clientfd, SOL_SOCKET, SO_LINGER, &lingerOpts, i);
        ///////
    
        /*
         * Connect to the server
         */
        status = connect(clientfd, (struct sockaddr *) &servAddr, sizeof(servAddr));
    
        if (status < 0) {
            System_printf("Error: client connect failed. (%d)\n",fdError());
            close(clientfd);
        }
    
        /*
         * Send a greetings message to the server
         */
        send(clientfd, msg, strlen(msg), 0);
    
        /* Init the Error_Block */
        Error_init(&eb);
    
        while ((bytesRcvd = recv(clientfd, buffer, TCPPACKETSIZE, 0)) > 0)
        {
            System_printf("RECEIVED %s\r\n",buffer);
            System_flush();
            //////
            break;
        }
    
    
        System_printf("tcpWorker stop clientfd = 0x%x\n", clientfd);
        close(clientfd);
    
        fdCloseSession(TaskSelf());
        Task_sleep(1000);
       }
    }
    

  • Hi Punith,

      Really glad that your issue is resolved. I have also learned something myself. I was just testing your code and I have an observation. On the server side, if I wait a little while (e.g. 2 or more seconds) after it detects the client connection close before sending data to the client, then I could keep number of open/close connection many more times than 11. 

  • Hi Charles,

    There is definitely something to do with the timings here. Though it was a small parameter that was altered provided a solution here, otherwise I was thinking of a lwIP kind of implementation which would mean a whole codebase change. I have tried lwIP FreeRTOS based implementations on other controllers it was working smoothly without any issues. 

    If you can check this in Wireshark it will give more insights into how the TCP connections and data exchanges are happening.