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.

RTOS: TCP Packet loss in TI-RTOS NDK

Tool/software: TI-RTOS

Hello,

I am using TM4C129EXL device connected to a wireless router. I have a TCP protocol based communication with the network other endpoint on WiFi. The TM4C129 act as a TCP socket server and I have an android TCP client. When the connection is established the client uses a blocking socket read method to wait for the packets from the uC, it is an unidirectional communication. (Its a kind of a data acquisition system.) Each packet that I send from the uC side I have a counter value that I increment in each send. The client is get notified about packet loss if the delta btw. each counter is greater than 1.

My situation is the following: When multiple wireless AP are in the same room ( WiFi channels are probably same -> possible congestion) I see large number of data loss. The TCP is a reliable protocol so no packet can loss. So, when the sender not receives ACK for a send() a re-transmission should start.

My question is the following. If the uC sending packets continuously and a retransmission happens, where is the data stored that needed to be re-transmitted? Does the API overwrite it?

I am generating a triangle shape signal on the uC side and on the receiver side I have some deformation on the signal. Some of the packets are lost I but the life goes and further packets are received. What about the lost packets? How many times does the uC try to retransmit the packets? What happens after the last failed retransmission btw the other packets are delivered well? is there any way to detect this event? On the client side, I don't have any exception...

Looking forward your kind reply.

P.S.: Can you recommend any TI document where I can get more detailed information about NDK TCP packet loss? 

  • Daniel,

    Sorry for the delay. I am contacting the development team to answer your question.

    ~Ramsey

  • OK. Let me know if something new come up.
  • Daniel,

    I have received the following information.

    The NDK gathers some statistics which might be helpful for you. There is a global variable called tcps which contains information regarding packet loss and retransmissions. Halt CCS. Enter the variable name into the watch window to see the data.

    Daniel Vamos said:
    My question is the following. If the uC sending packets continuously and a retransmission happens, where is the data stored that needed to be re-transmitted? Does the API overwrite it?

    The data that is ready to transmit is stored in the TCP send buffer. This buffer is the TX socket buffer for the TCP socket that send() was called on. TCP will keep the data in the buffer until an ACK is received.

    Let me know if you need more information.

    ~Ramsey

  • Hello,

    The following link was shared with me on a previous post: 

    well, which one is counting the lost packets? 

    Correct me if I am wrong:

    Sender tx the tcp packet to the destination. If ACK is not replied then tries to retransmit the same packet. No other packets are being send this time, the sender is trying to deliver the packet to the destination. If it fails than the connection is dropped. Is that true? Do you have some NDK specific documentation that I need to study?

    What is the number of retransmission in NDK? Can I change it? When we say that a TCP packet is dropped? Well what about the TCP reliability?  

    In my case, The sender is transmitting the packets via Ethernet to a router and the packets are forwarded via Wifi. Some of the packets are not arrives but the connection is still alive, further packets are coming. In this case my supposition is wrong, because the connection should be closed. 

    Thank you for your help,

  • Hi Daniel,

    Daniel Vamos said:
    What is the number of retransmission in NDK? Can I change it? When we say that a TCP packet is dropped? Well what about the TCP reliability?  

    You can see the retransmit times in the following array.  The stack is open source so you're free to modify these values and rebuilt/rerun your app:

    tcptime.c
    
    /* tcp_backoff - Exponential backoff applied to Timer Ticks */
    static UINT32 tcp_backoff[TCP_MAXBACKOFF+1] =
           { 1, 2, 4, 8, 16, 32, 64, 64, 64, 128, 128, 128, 128 };

    You can see how the retransmitting works TcpTimeoutRexmt().

    In TCP, each time a packet is sent, a timer is set.  If no ACK is RX'd before the timer expires, TCP tries to retransmit.  It again sets a timer, but this time the timeout value is increased (back off) to allow the other side more time to respond.  This repeats until the packet is finally received or the max back off time has been reached/tried.

    You can also see in the code that after the last try to retransmit, the connection is dropped.

    Daniel Vamos said:
    well, which one is counting the lost packets? 

    These stats should help you see more about what's going on in the above situation:

    tcps.RexmtTimeout++; // This increments when the retransmit timer expired.  It means that a packet was retransmitted, and an ACK was not RX'd in time

    tcps.TimeoutDrops++; // This will increment after the stack has tried to retransmit for the maximum number of times but ultimately failed - no ACK was ever RX'd

    Steve

  • Dear Steve,

    Thank you for your reply, but I have one last question.

    From the uC side I am generating TCP packets and sending them to a client in a frequency around 4 Hz. In case of network issues (congestion, etc... ) the packet can not be transmitted to the client within 250ms ( however the TCP trying to re-transmitting it over and over.). If the uC generates a new packet after 250ms, can the previous packet be lost? I mean, the old non transmitted packet is overwritten with the new packet that the uC generates?

    Thank you for your reply.
  • Daniel,

    TCP is reliable so it must keep a copy of the data you passed in the call to send() until it has been ACK'd by the other side.  Note that send() returning doesn't actually mean that the data was sent, only that it was successfully handed off to the TCP protocol layer [assuming a successful return from send()].  It's possible that data may be delayed by the TCP protocol before actually being transmitted, depending on congestion and or window sizes.

    If we never get an ACK, then the connection is dropped (covered in my previous post).

    Daniel Vamos said:
    If the uC generates a new packet after 250ms, can the previous packet be lost? I mean, the old non transmitted packet is overwritten with the new packet that the uC generates?

    In short, the answer is no.

    I think what you mean here is if you call send() a second time, and the data from a previous call to send() is still held up in the socket buffer because it hasn't been ACK'd yet.

    In this case, if there is room in the socket buffer, the data of your (2nd) send call will just be copied to the socket buffer and send() will return success.

    *If there is no room in the socket buffer, then the call to send() will block until more data in the socket buffer has been made available (i.e. until ACK of previously sent data have been received).  It won't overwrite existing data in the socket buffer.  Once space is available, the data will be written to the socket buffer and send() will return success (number of bytes successfully written).

    * --> Note that this is only true if your socket is blocking.  If your socket is non-blocking, then it can't wait for space in the socket buffer to become available and so send will return failure in this case (-1 and errno set to EWOULDBLOCK).

    Lastly, even if your socket IS blocking, it may only block for a limited time.  If space does not become available before socket block timeout is reached, then send() will also return -1 and errno of EWOULDBLOCK.

    Steve

    Edit: fixed a couple of minor mistakes

  • Thank you very much for your always detailed answers. Well I have no clue where my data is because on the receiver side I have some missing packets on the receiver side...
    Now we have a workaround for this problem and I am 99% sure about the issue is not on the uC side.
    I can accept your reply as an answer but some days or weeks later maybe I open a new thread as I collect more information about my problem.

    Thank you
  • No problem. I'd recommend capturing what's going out on the wire using Wireshark or tcpdump.

    Since your connection from the uC to the router is wired, you should be able do this using a smart switch with port mirroring (e.g. put a switch in between the uC and router, and then mirror the port that the uC is connected to, to another port on the switch. Then connect a PC running Wireshark to this mirrored port and run the capture).

    Or, if your router is running Linux, you could log into it and run tcpdump to see all of the traffic coming into the router from the uC.

    If you see all the data you send from the uC in the capture, then you know for sure that the NDK is doing its job and you could eliminate the uC from the list of possible culprits.

    Being able to see what's going out on the wire will greatly help you in figuring out the problem.

    Steve
  • Excellent idea! Thank you for your help!

    If I sense any NDK related issue, I will let you know!

  • Ramsey and I were still discussing this briefly today and thought of something else.


    In your call to send(), are you checking that the number of bytes sent is equal to the number of bytes you wanted to send? [i.e. return value of send()]


    E.g. if you wanted to send 50 bytes, did you check that send() returned 50?

    Steve

  • Hello,

    Thank you for the update. Here is my tx code:

    //start = Timestamp_get32();
    //
    // Send the Packet to the Client. If the Client is removed break will close the task and
    // close the socket
    //
    if(send(socket,txPacket,SM_TCP_PACKET_SIZE_RAMREADER,0) != SM_TCP_PACKET_SIZE_RAMREADER){
    	NOP();
    	// Break the Loop
    	break;
    }

    I am going to make a super simple example to demonstrate the situation. It takes me some days to make it due to the unlimited tasks that I have to accomplish. :)

  • Daniel,

    Can you try changing the above code to ensure that send() writes all of the bytes that you expect it to write?

    More or less change it something like the "send_all()" function that can be seen here:

    http://stackoverflow.com/questions/2618736/why-is-it-assumed-that-send-may-return-with-less-than-requested-data-transmitted

    Daniel Vamos said:
    if(send(socket,txPacket,SM_TCP_PACKET_SIZE_RAMREADER,0) != SM_TCP_PACKET_SIZE_RAMREADER){ NOP(); // Break the Loop break; }

    I'm thinking that you may be hitting a case where the socket buffer doesn't have enough space to fit SM_TCP_PACKET_SIZE_RAMREADER bytes (but it has room for some number of bytes less than this).


    In which case the call to send() above would return success (i.e. however many bytes it was able to successfully write), but the code above considers it a failure case because the if statement governs it as such.

    You could also check if you ever are hitting this in your fail case with a print out of the number of bytes actually rx'd within that if statement.  But, since it takes a long time to reproduce, maybe you should try the send_all() change AND add a print out to let you know if send() ever returned less than the number of bytes expected.

    Steve

  • Hello,

    Thank you for your suggestion. I'm going to organize a meeting for Monday when we test as you said. 

  • Curious if you had a chance to try this?

    Steve