µTasker Forum > NXPTM LPC2XXX and LPC17XX

Performance of TELNET like protocoll


Hi Mark,

I am currently testing the TELNET like protocol for data transfer to a TCP client. The aim is to achieve a maximum transfer rate and retransmission if necessary.

The task
  fnSendTelnetCmd(TTASKTABLE *ptrTaskTable)
is invoked periodically every 50ms.

This task checks if buffer is available
   jj = fnSendBufTCP(Tx_Telnet_Socket,(unsigned char *)&OurTask, TelTx.usLen, TCP_BUF_CHECK);

and if so it transfers the data:
  if (jj >0) {
qt = fnSendBufTCP(Tx_Telnet_Socket, (unsigned char *) &TelTx.Buf , TelTx.usLen,  (TCP_BUF_SEND  |  CP_BUF_SEND_REPORT_COPY)   );


The following settings have been left unchanged:
    #define TCP_BUFFER  2800   
    #define TCP_BUFFER_FRAME      1400

Everything is ok as long as 2100 or less bytes have to be transferred, i.e. every 50ms that amount of data goes out in 2 blocks - 1 is 1400 bytes long and the other one contains the remaining bytes. For instance 2100-1400=700 bytes.
I have checked that with WireShark.

Greater payloads lead to jj=0 (check for  available buffer size). jj then is 0 for several periods. No data is sent.

The decision whether or not to return 0 is made here in fnSendBufTCP():

if (tcp_tx->usWaitingSize + tcp_tx->usPacketSize + usDataLen > TCP_BUFFER) {
            tcp_tx->WakeTask = *ptrBuf;                // mark task to wake when buffer free
            return 0;                                       // not enough space to send intended buffer
        else { …}

  tcp_tx ->usWaitingSize = 0
  tcp_tx->usPacketSize = 900 = 0x384
  usDataLen = 2300

tcp_tx->usPacketSize seems to be the second block that not yet has been sent.
What could be the reason for that?
Is it a missing ACK? How should that be handled?

I could try to run fnSendTxBuf() several times with usDataLen<=1400, i.e. activate the Task and run uTaskerSchedule() several times
But is that really the recommended procedure?


Hi Martin

In buffered TCP mode the transmitted data will remain in the output buffer until acknowledged by the peer.
If the peer doesn't acknowledge for some time (eg. when the transmission is lost or the ACK is lost) the remaining size in the buffer that can accept more data will be reduced and so there may come a point where the data will no longer fit (as in your check).

If the peer acknowledges with a delay it may be worth increasing your buffer size so that you can fit in enough messages, but remember the following details too:
- the TCP operation uses windowing and will send as many frames as it can on each transmission
- when acknowledges are received from the peer it will acknowledge the amount of data received which can be more than one frame (these details are handled by the TELNET-like socket though)
- the peer may be using delayed ACK, which means that there will generally be a 150ms delay before it sends back an ACK to the first data packet (it is hoping to piggy-back the ACK with some data that may be sent back within this time). When a second frame is sent to the peer (which is possible due to the windowing operation) it will tend to trigger an immediate ACK - cancelling the peers delayed ACk operation since more than one frame of TCP data has been received.

Generally the choice of the TCP buffer size is probably the most important thing to get the throughput/delays optimised to your application. If the communication link is temporarily 'broken' the transmission will have to stop until it recovers, which requires a different strategy than having huge Tx buffers, but for the occasional transfer loss you may find the buffer size is the most important (you may want to reduce the transmission delay too - see defines in tcpip.h to keep the wait down). In a LAN packet loss should generally be very low so repetitions should be very rare - if this is not the case the cause should be looked into as well.



Hi Mark,

thank you for your immediate reply.

Increasing the buffer made it possible to send more data.
But as this buffer is in the heap and the amount of data I have to transfer in each cycle is rather high (it is sampled data), I cannot pass the whole size to fnSendBufTCP() as a parameter.

3 basic questions regarding the TELNET like protocol (raw mode) I would like to ask:
- Is it correct that  I do not have to care for the ACK and TCP will automatically free buffer occupied by fnSendBufTCP() as soon ACK is received?
- Will retransmission be done automatically? Or is it necessary to care for the event TCP_EVENT_REGENERATE?
- Will TCP_EVENT_PARTIAL_ACK be handled automatically?

I thought I could do the following to handle a bigger amount of data::
- In the  task that is called periodically I check for sufficient memory and then send 2 frames,  each with a length of 1400 (=TCP_BUFFER_FRAME).
(2 frames to avoid delayed acknowledge from the client.)

--- Code: ---jj = fnSendBufTCP(Tx_Telnet_Socket,(unsigned char *)&OurTask, BlockLen, TCP_BUF_CHECK);
if (jj) {
    DataLen -= BlockLen;
    qt = fnSendBufTCP(Tx_Telnet_Socket, ptBuf, BlockLen,  (TCP_BUF_SEND | TCP_BUF_SEND_REPORT_COPY)   );
--- End code ---
where BLOCKLEN=2800 and DataLen is the total amount of data to be sent, for instance 2900.
The result is qt=1400, probably because the second block is sent a bit later. Wireshark reports 2 frames of 1400 bytes each.

- The remaining bytes (100 in the example) shall be sent in the listener function when TCP_EVENT_ACK is received (and TCP has freed the buffers).
I set breakpoints and - as expected - the sending task is invoked first  and then the debugger stops when TCP_EVENT_ACK is received.

In the listener function:

--- Code: ---UTASK_TASK OurTask = TASK_TELNETCMD;  // 'x'
jj = fnSendBufTCP(Tx_Telnet_Socket,(unsigned char *)&OurTask,           BlockLen, TCP_BUF_CHECK);
--- End code ---

Curiously the 100 bytes only get sent at the beginning.
It seems that I am making a principal mistake as 2*1400 bytes are always sent(Wireshark). Also the listener is not invoked at least once per period.
Most likely the question is “Which event frees the buffers?” Would you agree?

Which setting in tcpip.h reduces transmission delay? Why would I want to have a delay?


Hi Martin

The TELNET-like socket uses a buffered TCP socket and handles all details of transmission, retransmission and the congestion window, meaning that the TELNET-like listner doesn't need to do any work in this respect. The listener is still passed events so that its code could monitor and react to progress but generally the transmitter can be considered as a buffer into which you can write as much data as fits and it will be transmitted as best as possible.

I am not sure about your results concerning sending multiple packets but i woudl suggest to just send bigger chunks, larger than the maximum TCP frame size, since the TELNET-like layer will automatically send this as efficiently as possible in multiple frames. As long as you send a chunk of data larger than the maximum frame size it will therefore be sent as two back-to-back TCP frames, which will also overcome delayed ack at the peer.

Note that tx buffers are freed when acknowldeged, whcih can be with a TCP_EVENT_ACK or a TCP_EVENT_PARTIAL_ACK, depending on how the peer responds.




I missed the question about the delay.
In fact I mean "repetition delay" and not "transmission delay" - when there is no acknowledgement to data. This is set in seconds by TCP_STANDARD_RETRY_TOUT.




[0] Message Index

Go to full version