if a tcp client send a packet, with sequence number from 10000 to 20000, to a tcp server. the tcp will respond with an ACK with seq_ack 20001.

if I intercept the TCP packet from the client, and split the packet into 2 tcp segments, one with seq from 10000 to 15000, and the other with seq from 15001 to 20000. And then these 2 TCP segments are sent to the TCP server. Assume that the second segment is lost in the path. The TCP server will respond an ACK with seq_ack 15001.

Now since the TCP client send a integral packet with seq 10000 to 20000, but it gets an ACK with 15001, from the client's point of view, this is weird. How will it react? In theory, the client should retransmit the bytes from seq 15001 to 20000, namely, the client will transmit new packets from seq 15001. But how about the practice, in TCP stack implementation, is it the same as in the theory?

I think in the TCP send buffer, when a tcp segment is sent, the segment still stays there until the ACK. When the ACK come, these bytes for the segment are cleared from the buffer. There is a pointer in the send buffer, when an ACK come, the pointer points to the location where the ack_seq corresponds to. The bytes that are below the ack_seq are cleared. In this way, the whole segment needn't be retransmitted?


This is called selective acknowledgement, and is already included in the TCP specification defined in RFC 2018. This would allow the client to indeed resend just bytes 15001 to 20000 (since they are in different packets/segments if you had split them as you say), but more interestingly, it even allows out-of-order acknowledgements.

From RFC 2018:

When receiving an ACK containing a SACK option, the data sender SHOULD record the selective acknowledgment for future reference. The data sender is assumed to have a retransmission queue that contains the segments that have been transmitted but not yet acknowledged, in sequence-number order.

Supporting SACK is not required by the TCP specification. If either the client or the server did not support selective acknowledgement, indeed all of the bytes 10000 to 20000 would have to be retransmitted.

In TCP stack implementation, is it the same as in the theory?

Usually SACK is supported, as the performance, efficiency, and latency gains are significant - especially in a network like the internet.

Indeed however, these assumptions should hold true even if you manually manipulate the packets as you stated. As per RFC 793, at minimum, the entire data window will have to be retransmitted, but the reciever does know that the recieved data is at least valid. For implementation details, Section 3.3 - Sequence Numbers from RFC 793.

For an outline of the entire process both with and without selective acknowledge support, see this article (which includes some very useful diagrams).

  • it is a bit strange to me, because TCP is stream-based, byte-oriented protocol. Why should it retransmit the whole segment? It seems to me that TCP without SAKC is segment-oriented stream protocol, but TCP with Sack is real byte-oriented. I think the RFC doesn't specifically elaborate on this. – misteryes May 22 '13 at 14:35
  • how TCP stack manage its send buffer, is it the same as what I wrote in the updated question. – misteryes May 22 '13 at 14:36
  • @misteryes this article outlines the process (with some great diagrams, too!). – Breakthrough May 22 '13 at 14:57
  • In the link you recommended, it seems that the author still discuss the problem in a segment-oriented way, not in real byte-oriented way. Isn't it? – misteryes May 22 '13 at 15:19
  • 1
    I knew SACK before I post this question. At the very beginning I don't think SACK has something to do with this question. In my opinion, if TCP is not byte-oriented but segment-oriented, then SACK should also be the same. The difference between SACK-enabled and SACK-disabled is that with SACK, TCP allows a sequence hole in ack_seq. But I thought the sequence hole corresponds to a segment. while according to your saying, the hole can be half/part of a segment. – misteryes May 22 '13 at 15:22

Segment sizes can (and do) change over the lifetime of a connection. Luckily, TCP has no need to record the segment size that individual packets were sent with previously. Therefore, it will do the following:

  1. Whenever an ACK arrives, advance the pointer to the first unacknowledged byte accordingly and discard any now-unneeded buffer.
  2. When the need arises for retransmission (Fast Retransmit or Timeout; NOT immediately after the receipt of the first ACK!), it will resend in the currently valid segment size starting from the pointer to the first unacknowledged byte.

Both operations are done independently of the segment size these bytes were originally sent in. So the theory should match most implementations.

Let me give some background to explain:

Does TCP use bytes or segments? To the application, TCP exposes a byte stream interface. Also, all the header fields and internal variables are in bytes. However, to transmit information, TCP chunks them up in segments, as sending bytes one-by-one would be pretty wasteful :-). Using byte counters everywhere has the advantage that the segment size does not need to remain constant over the lifetime of the connection:

  • Options are being introduced, e.g. piggybacking a SACK on a retransmit (real implementations will encounter this rarely, if at all)
  • The Path MTU changes, e.g. one link along the path changes to a lower MTU or the bottleneck MTU link is raised. This happens when tunnels are established (VPN, PPPoE) or the routing protocol selects a different-MTU link. This happens in IPv4 with Don't Fragment set (true for most modern TCPs); always in TCPv6).

BTW: SACK is not the answer here, as the receiver will (typically) only use SACK if it recognizes a hole in the byte stream (i.e., if a packet got lost but a following packet arrived).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.