Author Topic: TCP sending getting PARTIAL_ACKS  (Read 10208 times)

Offline johnr

  • Jr. Member
  • **
  • Posts: 91
    • View Profile
TCP sending getting PARTIAL_ACKS
« on: April 15, 2008, 10:04:24 PM »
HI Mark, I haven't been testing the TCP for a while, but I'm back on it.
I have a test server that I can send and rcv short messages. Everything
works OK but I sometimes get PARITAL_ACK events back. How should I handle
these ?

 Thanks,
 John

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: TCP sending getting PARTIAL_ACKS
« Reply #1 on: April 15, 2008, 10:28:16 PM »
Hi John

Partial ACK events are received when the ACK number of the received ACK doesn't correspond to the ACK number expected to the last outstanding TCP transmission.

If you are not sending more that one TCP frame at a time without first receiving an ACK to it you should in fact never receive partial ACKs. This could be a indication of an error somewhere in this case (for example I have had it when (unintentionally) overwriting the sockets management buffer so that its ACK counters were corrupted!!! [check the value of usPortLen - if it is larger than all data sent it is wrong somewhere: it is calculated from (unsigned short)(ptr_TCP->ulNextTransmissionNumber - rx_tcp_packet.ulAckNo)]

If you are sending 2 TCP frames before sending more this may happen - in this case it is best to simply ignore it. It means that the server has been fast enough to respond to the first frame and will probably also respond to the second very shortly. The ACK to the second is the important one.

If you are sending more than 2 (this is more complicated and requires management of the congestion window) it involves working out which part of the transmitted data has been acked and which of it is still outstanding. Buffered TCP does this so check that as a reference (eg. fnAckedTxWindowing()).

Regards

Mark

PS. Did you get further with the 9002 server?



Offline johnr

  • Jr. Member
  • **
  • Posts: 91
    • View Profile
Re: TCP sending getting PARTIAL_ACKS
« Reply #2 on: April 16, 2008, 12:23:53 AM »
Hi Mark,
 I have written a test TCP server using port 9002 running under Windows XP. I programmed it using Borland
Delphi 7, which comes with  Internet Server components ready to use.
I found that I would get an ABORT event on the initial connect. When this happens while I'm in the
"CONNECTING" state, I just keep retrying the connection, at 1 second intervals, until it works.
I logged the listen events and my states so I can see what is going on.
 My current test setup waits for the server to send a short packet, then responds back with a short packet,
waits for an ACK, then goes idle. The server sends packets at rates from 1 every .1 to 1 secs. uTasker checks
every 1 sec to see if it needs to respond, so the the server can send multiple packets before the uTasker
responds. It works for a while, but then I get partial acks. I'll take a closer look at my logs to see whats going on.

 Thanks,
 John
 
« Last Edit: April 16, 2008, 12:28:18 AM by johnr »

Offline johnr

  • Jr. Member
  • **
  • Posts: 91
    • View Profile
Re: TCP sending getting PARTIAL_ACKS
« Reply #3 on: April 16, 2008, 02:57:20 PM »
Mark, Here's a log of the my testing. The way it is setup is
that the uTasker task runs every 1 sec. When it sees that a
packet  arrived, it sends one back to the server. The uTasker
task sends packets of 12 bytes lengths and the server sends 9 byte lengths. The server sends packets at variable rates from
.1 to about 1 second.
 The PARTIAL_ACKS occur at the end of the
log. The PortLen returned was 12, which is the size that was
transmitted out. I stopped the server from sending data at this
point, got a REGEN, resent the data, then got an ACK. My protocol keeps track of packet sequence numbers so I know the
server was never getting an out of order or missed packet up to
this point.
 Under normal operations with our protocol, one side would
send a packet, then wait for a response back. One side would
never stream packets like the test server is doing here.
It looks like when the server stopped sending, we finally got the
ACK, instead of partial acks.
 Does this make any sense ?

 Thanks,
 John


Code: [Select]
0 - fnSetNextIMS_INIT --> OPEN_REQUESTED
0 - fnSetNextIMS Ok
1 - fnIMSListener() Event=CONNECTED State=OPENING
1 - fnSetNextIMS_OPENING --> IDLE
1 - fnSetNextIMS Ok
13 - fnIMSListener() Event=WIN_UPD State=IDLE
13 - fnIMSListener() Event=DATA State=IDLE
13 - fnHandleData() len=9 Offs=0
13 - fnSetNextIMS_IDLE --> PACKET_READY
13 - fnSetNextIMS Ok
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
13 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
13 - fnIMSListener() Event=DATA State=PACKET_READY
13 - fnHandleData() len=9 Offs=0
14 - setup_sendpkt(), seqnum=0
14 - sendpkt(), sending 12 bytes
14 - send_pkt() sent 12 bytes
14 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
14 - fnSetNextIMS Ok
14 - sendpkt returned 12
14 - fnIMSListener() Event=ACK State=WAIT_ACK
14 - fnSetNextIMS_WAIT_ACK --> IDLE
14 - fnSetNextIMS Ok
14 - fnIMSListener() Event=DATA State=IDLE
14 - fnHandleData() len=9 Offs=0
14 - fnSetNextIMS_IDLE --> PACKET_READY
14 - fnSetNextIMS Ok
14 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
14 - fnIMSListener() Event=DATA State=PACKET_READY
14 - fnHandleData() len=9 Offs=0
14 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
14 - fnIMSListener() Event=DATA State=PACKET_READY
14 - fnHandleData() len=9 Offs=0
14 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
14 - fnIMSListener() Event=DATA State=PACKET_READY
14 - fnHandleData() len=9 Offs=0
14 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
14 - fnIMSListener() Event=DATA State=PACKET_READY
14 - fnHandleData() len=9 Offs=0
14 - fnIMSListener() Event=WIN_UPD State=PACKET_READY
14 - fnIMSListener() Event=DATA State=PACKET_READY
258 - fnIMSListener() Event=WIN_UPD State=IDLE
258 - fnIMSListener() Event=DATA State=IDLE
258 - fnHandleData() len=9 Offs=0
258 - fnSetNextIMS_IDLE --> PACKET_READY
258 - fnSetNextIMS Ok
259 - setup_sendpkt(), seqnum=214
259 - sendpkt(), sending 12 bytes
259 - send_pkt(): fnSendTCP() error
259 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
259 - fnSetNextIMS Ok
259 - sendpkt returned 0
259 - fnIMSListener() Event=REGEN State=WAIT_ACK
259 - send_pkt() sent 12 bytes
259 - fnSetNextIMS_WAIT_ACK --> WAIT_ACK
259 - fnSetNextIMS Ok
259 - fnIMSListener() Event=ACK State=WAIT_ACK
259 - fnSetNextIMS_WAIT_ACK --> IDLE
259 - fnSetNextIMS Ok
259 - fnIMSListener() Event=WIN_UPD State=IDLE
259 - fnIMSListener() Event=DATA State=IDLE
259 - fnHandleData() len=9 Offs=0
259 - fnSetNextIMS_IDLE --> PACKET_READY
259 - fnSetNextIMS Ok
260 - setup_sendpkt(), seqnum=215
260 - sendpkt(), sending 12 bytes
260 - send_pkt() sent 12 bytes
260 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
260 - fnSetNextIMS Ok
260 - sendpkt returned 12
260 - fnIMSListener() Event=ACK State=WAIT_ACK
260 - fnSetNextIMS_WAIT_ACK --> IDLE
260 - fnSetNextIMS Ok
260 - fnIMSListener() Event=WIN_UPD State=IDLE
260 - fnIMSListener() Event=DATA State=IDLE
260 - fnHandleData() len=9 Offs=0
260 - fnSetNextIMS_IDLE --> PACKET_READY
260 - fnSetNextIMS Ok
261 - setup_sendpkt(), seqnum=216
261 - sendpkt(), sending 12 bytes
261 - send_pkt() sent 12 bytes
261 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
261 - fnSetNextIMS Ok
261 - sendpkt returned 12
261 - fnIMSListener() Event=ACK State=WAIT_ACK
261 - fnSetNextIMS_WAIT_ACK --> IDLE
261 - fnSetNextIMS Ok
262 - fnIMSListener() Event=WIN_UPD State=IDLE
262 - fnIMSListener() Event=DATA State=IDLE
262 - fnHandleData() len=9 Offs=0
262 - fnSetNextIMS_IDLE --> PACKET_READY
262 - fnSetNextIMS Ok
263 - setup_sendpkt(), seqnum=217
263 - sendpkt(), sending 12 bytes
263 - send_pkt(): fnSendTCP() error
263 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
263 - fnSetNextIMS Ok
263 - sendpkt returned 0
263 - fnIMSListener() Event=REGEN State=WAIT_ACK
263 - send_pkt() sent 12 bytes
263 - fnSetNextIMS_WAIT_ACK --> WAIT_ACK
263 - fnSetNextIMS Ok
263 - fnIMSListener() Event=ACK State=WAIT_ACK
263 - fnSetNextIMS_WAIT_ACK --> IDLE
263 - fnSetNextIMS Ok
315 - fnIMSListener() Event=WIN_UPD State=IDLE
315 - fnIMSListener() Event=DATA State=IDLE
315 - fnHandleData() len=9 Offs=0
315 - fnSetNextIMS_IDLE --> PACKET_READY
315 - fnSetNextIMS Ok
316 - setup_sendpkt(), seqnum=252
316 - sendpkt(), sending 12 bytes
316 - send_pkt(): fnSendTCP() error
316 - fnSetNextIMS_PACKET_READY --> WAIT_ACK
316 - fnSetNextIMS Ok
316 - sendpkt returned 0
316 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
316 - fnIMSListener() PortLen=12
316 - fnIMSListener() Event=DATA State=WAIT_ACK
316 - fnHandleData() len=9 Offs=0
318 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
318 - fnIMSListener() PortLen=12
318 - fnIMSListener() Event=DATA State=WAIT_ACK
318 - fnHandleData() len=9 Offs=0
319 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK

414 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
414 - fnIMSListener() PortLen=12
414 - fnIMSListener() Event=DATA State=WAIT_ACK
414 - fnHandleData() len=9 Offs=0
415 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
415 - fnIMSListener() PortLen=12
415 - fnIMSListener() Event=DATA State=WAIT_ACK
415 - fnHandleData() len=9 Offs=0
417 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
417 - fnIMSListener() PortLen=12
417 - fnIMSListener() Event=DATA State=WAIT_ACK
417 - fnHandleData() len=9 Offs=0
418 - fnIMSListener() Event=PARTIAL_ACK State=WAIT_ACK
418 - fnIMSListener() PortLen=12
418 - fnIMSListener() Event=DATA State=WAIT_ACK
418 - fnHandleData() len=9 Offs=0
421 - fnIMSListener() Event=REGEN State=WAIT_ACK
421 - send_pkt() sent 12 bytes
421 - fnSetNextIMS_WAIT_ACK --> WAIT_ACK
421 - fnSetNextIMS Ok
422 - fnIMSListener() Event=ACK State=WAIT_ACK
422 - fnSetNextIMS_WAIT_ACK --> IDLE
422 - fnSetNextIMS Ok

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: TCP sending getting PARTIAL_ACKS
« Reply #4 on: April 16, 2008, 03:53:18 PM »
Hi John

I think that I now understand why you are receiving partial acks - but I am not sure whether there is a problem with this or whether it is more to understand what is happening.

1. Assuming you are sending but the server is not then I would expect the following:
- transmission of 12 bytes
- after a delay of about 200ms (assuming delayed acks are not disabled at the server) an ACK to this frame. Since the ACK numer corresponds with expected ACK to all outstanding data it will generate a TCP_EVENT_ACK. You can then send further data if you want.
- This will be repeated for each frame sent

2. Assuming that the server is also sending data, sometimes the following will happen.
- transmission of 12 bytes
- the server sends data at approx. same time. This data will have the ACK count corresponding to before the 12 bytes of transmission. This will not generate a TCP_EVENT_ACK since it doesn't correspond to the expected ACK for all outstanding data (it is not an ack to teh 12 bytes...). Instead (if SUPPORT_PEER_WINDOW is active) it will generate a TCP_EVENT_PARTIAL_ACK with the value 12 (the difference between data ACKed and the outstanding expected ACK. This can be ignored in this case (buffered TCP will use it to calculate which part of outstanding data has actually been acked - eg it has previously sent 4 x 6 byte frames and it then knowns that this has acked the first 2 and the last 2 are still outstanding).
- the server MUST then send (possibly after a delay of about 200ms) a second ACK to the last 12 bytes which it hadn't yet received as it sent its last message. If this doesn't arrive you will eventually receive TCP_EVENT_REGENERATE (I hope...)

It is easiest to check this from a WireShark recording. If you are having a problem with this behaviour please send a recording (saved copy per mail so that I can use it to simulate and see the timings involved).

Further:
What does the following mean? "fnSendTCP() error"
Is it possible that the client and server are some how synchronised so that when the partical ack occurs once it seems to repeat the sequence over and over?

Regards

Mark

Offline johnr

  • Jr. Member
  • **
  • Posts: 91
    • View Profile
Re: TCP sending getting PARTIAL_ACKS
« Reply #5 on: April 16, 2008, 07:52:23 PM »
Mark,
 "fnSendTCP() error" gets logged when it returns <=0. I would then expect
a REGEN to resend the packet or I'll timeout waiting.
SUPPORT_PEER_WINDOW  is enabled for the project.
It's getting clearer now. I'll keep testing and logging.

 Thanks,
 John
 

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: TCP sending getting PARTIAL_ACKS
« Reply #6 on: April 16, 2008, 08:36:35 PM »
John

Normally fnSendTCP() will only fail due to NO_ARP_ENTRY - after ARP resolution the TCP_EVENT_REGENERATE would arrive very quickly afterward (not a timeout).
This would thus be a normal situation (especially on a busy network) but can be reduced by having a larger ARP table [ARP_TABLE_ENTRIES] (less flushes) or by enabling the define ARP_IGNORE_FOREIGN_ENTRIES, which will then only keep ARP entries which are really used by the application (rather than all 'seen' on the network).

Regards

Mark