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.

TM4C1294NCPDT: Socket does not receive any data after remaining idle for sometime

Part Number: TM4C1294NCPDT


I have created a TCP client which connects to MQTT broker and receives data through socket. I have used sample tcp echo example and TI-RTOS NDK stack for creating socket and connecting to broker. It works perfectly fine till the broker or server sends data at a frequency with time gap of 4 mins, ,but as the server send or publishes data after a time interval of more than 4 mins, the socket remains idle and does not receive anything from server/broker .which parameter set all these thing...I have found some similar parameters in tcpecho.cfg file...I tried to increase them but it didn't work.How should I keep the socket receiving all the time without bothering socket idleness?

Thanks

  • Hi Prachi,

    Can you try setting a keep alive time out for the socket?

    This can be achieved using the setsockopt() API with the socket option SO_KEEPALIVE.

    int skt;
    int optval;
    int optlen = sizeof(optval);
    
    // skt = socket(...);
    
    optval = 1;
    status = setsockopt(skt, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
    if (status == -1) {
        // error
    }

    Steve

  • Hi Steve,

    Thanks for your reply!

    I have set the parameters like this 

    server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (server == -1) {
            System_printf("Error: socket not created.\n");
            return;
        }
    
        memset(&localAddr, 0, sizeof(localAddr));
        localAddr.sin_family = AF_INET;
        localAddr.sin_addr.s_addr = inet_addr("198.41.30.241");  
        localAddr.sin_port = htons(1883);
    
    
        /* Check the status for the keepalive option */
        if(getsockopt(server, IPPROTO_TCP , SO_KEEPALIVE, &optval, &optlen) < 0) 
        {
            close(server);
            }
        printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
    
    
        /* Set the option active */
        optval = 1;
        optlen = sizeof(optval);
        if(setsockopt(server, IPPROTO_TCP , SO_KEEPALIVE, &optval, optlen) < 0) 
        {                  
            close(server);
           
        }
        printf("SO_KEEPALIVE set on socket\n");
    
        
        /* Check the status again */
        if(getsockopt(server, IPPROTO_TCP , SO_KEEPALIVE, &optval, &optlen) < 0) {
            
            close(server);
            
        }
        printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
    
    
        while(connect(server, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0){
            SysCtlDelay(400000);
        }
    
        data.clientID.cstring = "me";
        data.keepAliveInterval = 0;
        data.cleansession = 1;

    The tcpecho.cfg file has default time setting for TCP module like:

    Socket keep idle time(0.1 seconds)= 72000

    Socket keep alive probe interval time(0.1 seconds)=750

    Socket keep alive probe timeout(0.1 seconds)=6000

    As per my understanding  "Socket keep idle time" allows your socket to be alive even after remaining idle for time set here, while the "Socket keep alive probe interval time" is used for setting a time interval for sending keep alive probe packet to server(...or server sends it to peers?) and the third parameter "Socket keep alive probe timeout" would determine a time to answer a keep alive probe request before disconnection.....am I right ?

    I have used the setsockopt API to create a socket specified with SO_KEEPALIVE value with above values configured in tcpecho.cfg. I want to keep the socket alive even after idleness of sometime...I do not want to close it after some idleness rather it should receive data from server even after some inactivity.

    How would I achieve such functionality?

    Best Regards,

    Prachi

  • Hi Prachi,

    It looks like you have the wrong level in your setsockopt() call:

    Prachi Patil said:
    if(setsockopt(server, IPPROTO_TCP , SO_KEEPALIVE, &optval, optlen) < 0)

    That option should be SOL_SOCKET.

    Do you not get an error with the above call?

    Steve

  • Hi Steve,

    Steven Connell said:

    That option should be SOL_SOCKET.

    Do you not get an error with the above call?

    Earlier  when I set that option to "IPPROTO_TCP" I didn't get an error, then code executed as it should be, I checked that SO_KEEPALIVE option is set on the socket by checking optval by getsockopt API before and after setsockopt API.

    Now I've set the option to "SOL_SOCKET" but still the socket does not remain alive after some reception inactivity. The tcpecho.cfg configures following three parameters only to a socket which is specified by SO_KEEPALIVE option....Can you guide me about setting these parameters for a socket to remain alive for long time.

    1. Socket keep idle time
    2. Socket keep alive probe interval time
    3. Socket keep alive probe timeout

    Thanks

    Prachi

  • Prachi Patil said:
    As per my understanding  "Socket keep idle time" allows your socket to be alive even after remaining idle for time set here, while the "Socket keep alive probe interval time" is used for setting a time interval for sending keep alive probe packet to server(...or server sends it to peers?) and the third parameter "Socket keep alive probe timeout" would determine a time to answer a keep alive probe request before disconnection.....am I right ?

    You're on the right track.

    TCP keep probes are meant to check if "the other side" is still there, after not hearing anything from that other side for a while. For example, an idle socket that hasn't seen any communication for a few minutes has no way of knowing if this is due to the other side simply having nothing to send, or if the connection was severed. Keep probes are kind of a "hey, are you there still?" message. And if you get a reply, then you know the connection is still present and wasn't severed. Either side (server or client) can send keep probes when a connection has gone idle for some time.

    So, how can we define "gone idle for some time"? That brings us to the parameters you have found.

    1. keep idle time - this is the length of time to allow a connection to be idle before starting to worry if the connection has been severed. After this time, the stack decides to start sending out keep probes to see if the other side's still there.
    2. keep interval - once the stack starts sending keep probes (as described in #1 above), this parameter governs the frequency at which those probes are sent out.
    3. keep max idle - this is the 2nd idle time, if you will. Once the keep probes start going out, if we aren't getting any response to the probes, this is the max amount of time that the stack will wait before closing down the connection. Basically, if this time is reached, we assume that the connection was severed.

    Prachi Patil said:
    but still the socket does not remain alive after some reception inactivity

    Hmm... something still doesn't seem right here. If you have indeed set the keep alive option correctly, and have the default keep idle time of 72000 (2 hours), then the app shouldn't even start the keep alive  probe process until after 2 hours of inactivity ... but you're seeing an issue after 4 minutes.

    Prachi Patil said:
    as the server send or publishes data after a time interval of more than 4 mins, the socket remains idle and does not receive anything from server/broker

    Can you please take a Wireshark capture at this time? I'd like to see if the stack is responding to the server with an error packet of sorts.

    Note that you need to have the proper network topology to capture the packets. Is your MQTT server running on a PC that you're using? Or is it some  remote server on the WAN?

    Hopefully you're connecting to an MQTT server on a Linux box or some sort of PC. Then, you can run Wireshark on that PC. Otherwise, you need to use a hub or a switch that has port mirroring.

    Steve

  • One more thing to mention:

    Prachi Patil said:
    printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

    printf() calls like this can be problematic for real time systems. You should use an RTOS friendly means of printing, instead.

    For example, you can do this:

    #include <xdc/runtime/System.h>

    System_printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

    System_flush(); // can be done "sometime later" to flush the buffer to standard out.

    Steve

  • Hi Steve,

    Thanks a lot for your elaborate reply!

    Steven Connell said:
    Hmm... something still doesn't seem right here. If you have indeed set the keep alive option correctly, and have the default keep idle time of 72000 (2 hours), then the app shouldn't even start the keep alive  probe process until after 2 hours of inactivity ... but you're seeing an issue after 4 minutes.

    I have used tcphandler task  to connect to mqtt like....

    Void tcpHandler(UArg arg0, UArg arg1)
    {
          //  fdOpenSession(TaskSelf());
    
            int                status;
            int                clientfd;
            //  int                server;
            struct sockaddr_in localAddr;
            struct sockaddr_in clientAddr;
            int                optval;
            int                optlen = sizeof(optval);
            socklen_t          addrlen = sizeof(clientAddr);
            Task_Handle        taskHandle;
            Task_Params        taskParams;
            Error_Block        eb;
    
            MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
            int rc = 0;
            int mysock = 0;
            unsigned char buf[200];
            int buflen = sizeof(buf);
            int msgid = 1;
            MQTTString topicString = MQTTString_initializer;
            int req_qos = 0;
            char* payload = "mypayload";
            int payloadlen = strlen(payload);
            int len = 0;
    
    
    
            server = NDK_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            if (server == -1) {
                System_printf("Error: socket not created.\n");
                return;
            }
    
            memset(&localAddr, 0, sizeof(localAddr));
            localAddr.sin_family = AF_INET;
            localAddr.sin_addr.s_addr = inet_addr("198.41.30.241");
            localAddr.sin_port = htons(1883);
    
    
            /* Check the status for the keepalive option */
            if(NDK_getsockopt(server,  SOL_SOCKET , SO_KEEPALIVE, &optval, &optlen) < 0)
            {
                close(server);
            }
            System_printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
            System_flush();
    
    
            /* Set the option active */
            optval = 1;
            optlen = sizeof(optval);
            if(NDK_setsockopt(server, SOL_SOCKET , SO_KEEPALIVE, &optval, optlen) < 0)
            {
                close(server);
    
            }
            System_printf("SO_KEEPALIVE set on socket\n");
            System_flush();
    
            /* Check the status again */
            if(NDK_getsockopt(server,  SOL_SOCKET , SO_KEEPALIVE, &optval, &optlen) < 0) {
    
                close(server);
    
            }
            System_printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
            System_flush();
    
            while(NDK_connect(server, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0){
                SysCtlDelay(400000);
            }
    
            data.clientID.cstring = "me";
            data.keepAliveInterval = 0;
            data.cleansession = 1;
    
                   SysCtlDelay(400000);
           }
        len = MQTTSerialize_connect(buf, buflen, &data);
        rc = NDK_send(server, buf, len,NULL);
    
        /* wait for connack */
        if (MQTTPacket_read(buf, buflen, getdata) == CONNACK)
        {
            unsigned char sessionPresent, connack_rc;
    
            if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
            {
                System_printf("Unable to connect, return code %d\n", connack_rc);
                System_flush();
                return;
            }
        }
        else
            return;
    
        /* subscribe */
        topicString.cstring = "sub9/129";
        len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
    
        rc = NDK_send(server, buf, len,NULL);
        if (MQTTPacket_read(buf, buflen, getdata) == SUBACK)  /* wait for suback */
        {
            unsigned short submsgid;
            int subcount;
            int granted_qos;
    
            rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
            if (granted_qos != 0)
            {
                System_printf("granted qos != 0, %d\n", granted_qos);
                System_flush();
                return;
            }
        }
        else
            return;
    
        /* loop getting msgs on subscribed topic */
        // topicString.cstring = "TIVA/e";
                while (1)
                {                                                  /* transport_getdata() has a built-in 1 second timeout,your mileage will vary */
        if (MQTTPacket_read(buf, buflen, getdata) == PUBLISH)
        {
            unsigned char dup;
            int qos;
            unsigned char retained;
            unsigned short msgid;
            int payloadlen_in;
            unsigned char* payload_in;
            //   int rc;
            MQTTString receivedTopic;
    
            rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
                                         &payload_in, &payloadlen_in, buf, buflen);
            System_printf("message arrived::   %.*s\n", payloadlen_in, payload_in);
            System_flush();
        }
          }
        System_printf("disconnecting\n");
        System_flush();
        len = MQTTSerialize_disconnect(buf, buflen);
        rc = NDK_send(server, buf, len,NULL);
        close(server);
    // fdClose(server); // fdCloseSession(TaskSelf());
    }

    As I'm new to RTOS, I'm not able to identify where the issue is.. I think idle task runs after some time and if we publish some data on MQTT during idle task is running, the tcp client does not receive it....How can stop idle task from running and keep the tcphandler task to be running and socket alive all the time?

    I have captured wireshark network traffic for MQTT protocol where I published two messages at a interval of more than 4 mins... but the tm4c129 didn't get the second message but in network traffic the second published message can be seen..also ping request sent and ping response also can be seen after 4 mins of inactivity....is it may happen once idle task starts running, the socket does not receive or read from socket?

    I also thought of opening and closing the socket in a while(1) loop...will that be useful?

    Wireshark MQTT ping snippet.zip

    Prachi

  • Hi Prachi,

    Prachi Patil said:
    I think idle task runs after some time and if we publish some data on MQTT during idle task is running, the tcp client does not receive it....How can stop idle task from running and keep the tcphandler task to be running and socket alive all the time?

    The idle Task is always running in TIRTOS. It's just a background thread that runs when no other thread is running. You might be halting the program and seeing that the PC is in the idle thread and thinking that you're only ever in that. While this could be true, there's probably several other task threads running in the system, and the OS is switching between them.

    Have you used the ROV tool? Please give it a try when you see this issue. You can find it in CCS under "Tools -> ROV". Note that you must halt the processor to use ROV (it's a stop mode tool).

    Once you open it, you can click on the Task module to see the Task threads and their current execute states in your application. It's a very useful tool, I'll insert a screen shot below.

    You should see your tcpHandler Task in the Task view. If you don't, it means that it has exited and the next step is to find out why.

    If it has not exited, it may be blocked, maybe on the call to MQTTPacket_read() inside your while loop.

    Anyway, give that a try. Please post back a screen shot of what you see in ROV's Task view once you are able to do this, too.

    Moving on, I did a quick scan of your code and have a few recommendations:

    Prachi Patil said:
    // int server;

    Prachi Patil said:
    server = NDK_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    Is 'server' a global variable? I see the declaration commented out above.  Also, NDK_socket returns type HANDLE, so you should declare server as that (instead of int). It's easy to get confused with the NDK_socket() and other "POSIX like" socket APIs. They are very similar but have some differences such as types returned and parameter types.

    Prachi Patil said:
    if (server == -1) {

    I would change this to "if (server = INVALID_SOCKET) {"

    Prachi Patil said:
    close(server);
    // fdClose(server);

    This is another difference between the NDK_socket() API and its POSIX cousin socket() (used in a typical Linux app, for example). The POSIX style APIs return an integer file descriptor which you should call close() on. But for the NDK_socket() API, it returns a pointer and should be closed by calling fdClose(). Again, this is easy to get confused.

    So, I would change all of your close(server) calls to be fdClose(server)

    Actually, the app may be failing because of one of these close() calls.

    Prachi Patil said:
        if (MQTTPacket_read(buf, buflen, getdata) == SUBACK)  /* wait for suback */
        {

    ...

       }
        else
            return;

    Looking at the:

       else
            return;

    In the above code. Can you change this to print out a message here? You might be hitting this return and exiting from the tcpHandler Task thread.

    Steve

  • Prachi,

    What's the status with this?

    Todd
  • Hello Steven and Todd,

    I have been caught up in another task so didn't get time to look for the solution suggested by Steven, but as I'll be free from the current work ,I will check this also and will keep you posted and Steven as well.

    Any ways...thanks a lot for your help!

    Best Regards.
    Prachi
  • Hi Prachi,

    Any update on this?

    Todd

    [4/16 update...I'm marking this as TI thinks resolved. You can post a reply to re-open it.]

  • Hello Todd,

    Thanks for the update....I haven't got time to resolve this issue( caught up in another project)... So ,Its better, that this should be marked as resolved for the indefinite period to be back and to work on this issue. I'll reopen it when necessary.

    Prachi