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.

SIMPLELINK-CC32XX-SDK: Fastest way to receive data as TCP Client from a socket using Simplelink functions

Part Number: SIMPLELINK-CC32XX-SDK
Other Parts Discussed in Thread: CC3235MODSF,

Hello all,

I am developing an application as a TCP client using the following components:

    Custom hardware with CC3235MODSF
    SIMPLELINK-CC32XX-SDK Version: 5.10.00.02
    Service Pack Version: 4.1.0.28

The aim is to be able to receive data from the socket as fast as possible. The size of the data that will come from the TCP server is not constant. The communication on the socket is full duplex. So, the data from the TCP server might be received at anytime and also the TCP client can send data at anytime.

Due to these requirements, I am assuming I have to use a thread to either poll the socket very frequently or block the socket until 1 byte is received. If I poll the socket as frequent as I require, the MCU is late for processing other operations within other threads with lower priority. If I block the socket, only after that one byte is received I set the socket non-blocking and receive rest of the data bytes. However, that is also not fast enough as I can see from my debug timings.

Here are the functions that I call for these two different ways:

/* Create a client socket. */
sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
/* Try to connect to server. */
sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
/* Set socket as non-blocking. */
nonBlocking = TRUE;
rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
/* Begin receiving loop. */
while(1)
{
    /* Try receiving first byte several times. */
    for(i = 0 ; i < 100 ; i++)
    {
        /* Check socket to receive first byte. */
        rs = sl_Recv(sd, gp_buff, 1, SL_MSG_DONTWAIT);
        /* Check if there is no data. */
        if(SL_ERROR_BSD_EAGAIN == rs)
        {
            /* Sleep to try again later. */
            usleep(1000);
        }
        else
        {
            /* Break the for loop. */
            break;
        }
    }
    /* Check if first byte received. */
    if(1 == rs)
    {
        /* Receive rest of data. */
        rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
        
        /* Process data.... */
    }
    /* Check if there is no data. */
    else if(SL_ERROR_BSD_EAGAIN == rs)
    {
        /* Sleep task to try again later. */
        usleep(100000);
    }
    /* Check if there is an error. */
    else
    {
        /* Break the loop. */
        break;
    }
}

/* Create a client socket. */
sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
/* Try to connect to server. */
sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
/* Set socket as non-blocking. */
nonBlocking = TRUE;
rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
/* Begin receiving loop. */
while(1)
{
    /* Block socket to receive first byte. */
    rs = sl_Recv(sd, gp_buff, 1, SL_MSG_DONTWAIT);
    /* Check if first byte received. */
    if(1 == rs)
    {
        /* Receive rest of data. */
        rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
        
        /* Process data.... */
    }
    /* Check if there is an error. */
    else
    {
        /* Break the loop. */
        break;
    }
}

On the other hand, if I try a dummy scenario which I know exactly how many bytes that the TCP server is going to send, I can see that the communication happens very fast.

I have tried using sl_Select with trigger mode as well but as I am using TI-RTOS, I read in the forum that this was not recommended.

Please let me know if there is a better way to handle this TCP communication.

Best,

Ogulcan

  • For a streaming socket such protocol that doesn't define the length of the the payload is not common. 

    I guess if you use RTOS - the blocking method is preferred (I saw that you defined the socket as non blocking in both code samples).

    Are you defining the protocol on the server side? If so then change it so you will first block reading the header (payload size), then block reading the payload.

    Br,

    Kobi

  • Hi Kobi,

    Thank you for your answer. This is a basic terminal emulator application where there is no protocol. The data is sent as ASCII with several control sequences in between. Therefore, there is no header where I can read the payload.

    You are correct, it looks like I copied the second piece of code wrong. Here is how it should have been:

    /* Create a client socket. */
    sl_Socket(SL_AF_INET, SL_SOCK_STREAM, 0);
    /* Try to connect to server. */
    sl_Connect(sd, (SlSockAddr_t *)&addr, sizeof(SlSockAddr_t));
    /* Begin receiving loop. */
    while(1)
    {
    	/* Set socket as blocking. */
    	nonBlocking = FALSE;
    	rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
        /* Block socket to receive first byte. */
        rs = sl_Recv(sd, gp_buff, 1, 0);
        /* Check if first byte received. */
        if(1 == rs)
        {
    		/* Set socket as non-blocking. */
    		nonBlocking = TRUE;
    		rs = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlocking, sizeof(nonBlocking));
            /* Receive rest of data. */
            rs = sl_Recv(sd, &gp_buff[1], 4095, SL_MSG_DONTWAIT);
            
            /* Process data.... */
        }
        /* Check if there is an error. */
        else
        {
            /* Break the loop. */
            break;
        }
    }

    As we are not able to define any protocol for this application, your suggestion is not possible. What would you suggest in this case? Is blocking read first byte and non-blocking read for the rest is a good way to handle this socket? Or maybe is it better to read one byte at a time?

    Best,

    Ogulcan

  • It depends on the nature of the traffic.

    If you expect bursts of data, you may try the non-blocking method although it is not optimal as well. 

    If the data comes slowly (such as when from a human source) then waiting (blocking) for 1B at a time may work better.  

    You can also consider using the blocking with SL_SO_RCVTIMEO set to low value.

    Finally, if you do control the server side also, i would still add a short header with length before the transmission of each chunk. If you can't control the server - than i understand this is impossible.

    Br,

    Kobi 

  • Hi Kobi,

    The size of data differs at each step of the application. Sometimes it is just a few bytes but sometimes it can go up to a burst of 2500 bytes.

    I will try using low timeouts with SL_SO_RCVTIMEO as well. Then, I will compare timings of each method and hopefully decide to go forward with one of them.

    Unfortunately we do not control the server side. The server is controlled by our customer and the aim is to integrate our device to their system with as little change as possible on their side. I will try to request this change from them but I am not sure whether it is possible even if they are willing to.

    Thank you very much for your help.

    Best,

    Ogulcan