Page 1 of 1

Rapid TCP writes are inconsistent SBL2eXA

Posted: Mon Feb 24, 2014 9:01 am
by btse
So I have this small little program that reads the values of the input pins, and then sends the value over a TCP socket.
I have it set up so that when a client first connects to the TCP socket, the Netburner will send out the current value of each pin.
The TCP message takes the form of "SOCKET_NUM,VALUE\n".

Inside of the socket's TcpAccepted callback, I have this little piece of code. I am using a queue to transfer the messages to the main loop, where I am doing the actual TCP sending.

Code: Select all

for (int i = 7; i < NUM_PINS; i++) {
    int currState = Pins[i].read();
    int msg = (i << 8) | (currState & 0xFF);
    if (OSQPost(&pinQueue, (void *) msg) == OS_Q_FULL) {
        iprintf("pinQueue was full\r\n");
    }
}
And here is the code inside of my main loop.

Code: Select all

void * pinQueueStorage[PIN_QUEUE_SIZE];
OSQInit(&pinQueue, pinQueueStorage, PIN_QUEUE_SIZE);
while (1) {
    BYTE err;
    void * pData = OSQPend(&pinQueue, 0, &err);
    if (gpio_sock) {
        if (pData) {
            int message = (int) pData;
            int pin = (message >> 8) & 0xFF;
            int value = (message & 0xFF);
            tcp_iprintf(gpio_sock, "%d,%d\r\n", pin, value);
        } else {
            iprintf("OSQPend failed with error code: %d\r\n", err);
        }
    }
}
The concept and code works, but after doing some testing, I have found that the sending of the messages over the TCP sockets is sometimes delayed.
For example, with the above code, if I connect to the socket using telnet, I will get a response of

Code: Select all

7,1
8,1
9,1
10,1
11,1
12,1
even though the pins range from 7-15. After about 10 seconds, the rest of the pin messages will eventually be sent out and received.

Code: Select all

13,1
14,1
15,1
I have found 2 solutions so far that fix this problem. If I put either a iprintf("Anything inside of here"), or a OSTimeDly(1) after the tcp_printf(), then all of the messages will be sent out and received immediately. This leads me to believe that there is some timing issue going on. I was wondering if anyone knew what was really going on, and if there is a proper fix for it. My 2 solutions seem pretty hacky to me, and I do not fully understand why they even fix the issue. Thanks!

Re: Rapid TCP writes are inconsistent SBL2eXA

Posted: Mon Feb 24, 2014 1:59 pm
by rnixon
Sometimes telnet can buffer things. The way to know for sure would be to do a wireshark capture and see when the data is actually sent, multiple packets vs single packet, etc.

Re: Rapid TCP writes are inconsistent SBL2eXA

Posted: Tue Feb 25, 2014 7:32 am
by btse
I loaded up Wireshark to see what's going on. The packet with the rest of the message is never being sent out. It looks like it is being buffered up on the Netburner side. Is there any way to flush a TCP socket? I couldn't find anything after searching around.

Also another note:
When the issue occurs, the messages are generally bundled in a single packet, whereas, when I apply my "hacky" fix, each message is in its own packet.

Re: Rapid TCP writes are inconsistent SBL2eXA

Posted: Tue Feb 25, 2014 8:29 am
by pbreed
What are you connecting to?

It could be a window problem... with the other side TCP connection....

A couple of other things to try...
If your just starting, try the tcpserver or tcoservermulti examples using the TCP buffers class and see how that goes for you...
WE try to discourage people using the TCP callback stuff as its real easy to get that wrong.

If you want to use the tcp call back interface
The first thing I would do is to not transmit from the accept call back...
IE The Accept call back happens in a system level task, and I'm not sure transmitting from there is a good thing....

Re: Rapid TCP writes are inconsistent SBL2eXA

Posted: Tue Feb 25, 2014 5:05 pm
by roland.ames
Maybe have a look at using socket options:

from tcp.h

Code: Select all

#define SO_NONAGLE 2
#define SO_NOPUSH 4

Code: Select all

                setsockoption( fd, SO_NONAGLE );
                clrsockoption( fd, SO_NOPUSH );


I don't have much info on how exactly these work or any spare time right now, but maybe someone else can provide info