§3.5.4TCP Reliable Data Transfer

Transport layer Kurose & Ross pp. 238–245 · ~19 min read

  • duplicate acknowledgement
  • fast retransmit
  • selective acknowledgement
  • delayed acknowledgement
  • timeout doubling

Where you are

  • Application layer
  • Transport layer you are here
  • Network layer
  • Link layer
  • Physical layer

TCP (Transmission Control Protocol) recovers from loss with one timer and a counting trick: three acknowledgements that ask for the same byte mean the segment after it is gone.

Words you will meet

  • SendBase — the sequence number of the oldest unacknowledged byte.
  • Duplicate acknowledgement — a second acknowledgement asking again for a byte already asked for.
  • Fast retransmit — resending on three duplicates, without waiting for the timer.
  • Delayed acknowledgement — waiting up to 500 ms so one acknowledgement can cover two segments.
  • SACK — an optional extension that lets a receiver acknowledge out-of-order segments individually.

Why this matters

IP (Internet Protocol) guarantees nothing. TCP (Transmission Control Protocol) guarantees that the byte stream a process reads out of its receive buffer is uncorrupted, without gaps, without duplication, and in sequence — exactly the stream the other side wrote.

This section is how. It is also where section 3.4’s question finally gets answered. TCP has cumulative acknowledgements like Go-Back-N and retransmits one segment at a time like selective repeat, and the book’s verdict is that it is neither.

The sender, in three events

Section 3.4.4 assumed a timer per outstanding packet, which is conceptually easiest. In practice that bookkeeping costs more than it is worth, so RFC (Request For Comments) 6298 recommends a single retransmission timer, however many segments are outstanding. Everything below follows that recommendation.

Figure 3.33 — the simplified TCP sender, one event at a time
0 — Two variablesstep 1 of 4
NextSeqNum = InitialSeqNumber · SendBase = InitialSeqNumberSendBaseoldest unacknowledged byteNextSeqNumwhere the next segment starts

SendBase is the sequence number of the oldest unacknowledged byte — so SendBase − 1 is the last byte known to have arrived correctly and in order. NextSeqNum is where the next new segment will start.

Two variables and three events. Everything TCP does for reliability in the simple case is here; fast retransmit adds one branch to the third event.

Read all steps as text
  1. 0 — Two variablesSendBase is the sequence number of the oldest unacknowledged byte — so SendBase − 1 is the last byte known to have arrived correctly and in order. NextSeqNum is where the next new segment will start.
  2. 1 — Data received from the application aboveCreate a segment with sequence number NextSeqNum. If the timer is not already running, start it. Pass the segment to IP. Then advance NextSeqNum by the number of bytes just sent — not by one, because the numbering counts bytes.
  3. 2 — The timer expiresRetransmit the not-yet-acknowledged segment with the SMALLEST sequence number, and restart the timer. One segment — not the whole outstanding window. That single word is most of the difference from Go-Back-N.
  4. 3 — An acknowledgement arrives, carrying value yIf y is greater than SendBase, it acknowledges something new: move SendBase up to y, and restart the timer if any segments are still outstanding. If y is not greater, it is a duplicate — and in the simplified sender, nothing happens at all.

In plain words

Two variables and three events, and the whole of simple TCP reliability is in them.

The detail worth pausing on is in event 2: on a timeout, TCP resends the segment with the smallest unacknowledged sequence number. One segment. Go-Back-N would resend every unacknowledged segment, and that single word is where the two protocols part company.

Four scenarios

Figures 3.34, 3.35, 3.36 and 3.37 — four things that can happen

The data arrived. Only the acknowledgement was lost, so the sender times out and resends something the receiver already has.

message 4 of 4
Host AsenderTimeHost BreceiverTimetimeoutSeq=92, 8 bytesACK=100Seq=92, 8 bytes (resent)ACK=100

Click any arrow to see what that message says and why it is sent.

The same two hosts every time. Switch between them and watch how little the sender has to do to cope with each.

Read this diagram as text
  1. Host A sends Seq=92, 8 bytes to Host B. Sequence number 92 means this segment’s first byte is byte 92 of the stream. Eight bytes, so it covers 92 through 99.
  2. Host B sends ACK=100 to Host A — lost. The receiver has bytes 92–99 and now expects byte 100, so it acknowledges with 100 — one past the last byte received. The acknowledgement is lost on the way back.
  3. Host A sends Seq=92, 8 bytes (resent) to Host B — retransmission. The timer expired. The sender has no idea whether the data or the acknowledgement was lost, and does not need to know.
  4. Host B sends ACK=100 to Host A. The receiver sees from the sequence number that it already has these bytes, so it discards the data — and acknowledges again, because the sender is clearly still waiting.

Lifelines, left to right: Host A (host), Host B (server).

Scenario b is the one that separates TCP from Go-Back-N

Two segments are outstanding and both arrive perfectly. Both acknowledgements are slow. The timer for segment 92 expires — and TCP resends only segment 92.

Go-Back-N in the same situation would resend segment 92 and segment 100, even though segment 100 arrived intact. TCP does not, and by the time ACK=120 gets through, segment 100 never needs resending at all.

Scenario c makes the same point from the other side: a lost acknowledgement costs nothing as long as a later cumulative one arrives before the timer runs out.

Doubling the timeout

One modification most implementations make, and it is not really about reliability.

Whenever a timeout occurs, TCP retransmits as described. But it then sets the next timeout to twice the previous value, instead of deriving it from EstimatedRTT and DevRTT as section 3.5.3 described. So 0.75 s becomes 1.5 s, and then 3.0 s. The intervals grow exponentially with each successive retransmission of the same segment.

The doubling applies only to repeated timeouts. When the timer is started after either of the other two events, the interval goes back to being computed from the most recent EstimatedRTT and DevRTT.

Why exponential, and why here

Timeout doubling provides a limited form of congestion control, and it is the first congestion control in this chapter.

A timer expiring is most likely caused by congestion: too many packets arriving at one or more router queues along the path, causing drops and long delays. If every source responded by retransmitting persistently, the congestion would get worse. Backing off exponentially is a way of not doing that.

The same idea appears at the link layer in Ethernet’s CSMA/CD (Carrier Sense Multiple Access with Collision Detection) , in chapter 6. Sections 3.6 and 3.7 take it much further.

Fast retransmit

The trouble with timeout-triggered retransmission is that the timeout period can be long. From section 3.5.3, it is the average round trip plus four deviations, and it doubles on every retry. A sender that waits it out on every loss adds a great deal to the end-to-end delay.

Often the sender can tell much sooner, by noticing duplicate acknowledgements .

Table 3.2 — when a TCP receiver sends an acknowledgement [RFC 5681]
TCP receiver action

Cells marked ⓘ have an explanation — click to read it. Sortable columns have a ↕ in the heading.

Read the third row twice. It is the one that makes fast retransmit possible, and it is the receiver’s only way of reporting a gap.

Notice the first row: an in-order segment does not produce an immediate reply at all. That is a delayed acknowledgement , and it exists so that one acknowledgement can often cover two segments.

When a receiver gets a segment with a sequence number larger than the next expected one, it can see a gap — a missing segment, from loss or from reordering. Since TCP has no negative acknowledgement, it cannot say so directly. So it re-acknowledges the last in-order byte it has, which produces a duplicate.

Because a sender usually has many segments in flight, one loss produces a run of these back to back.

The rule, and the off-by-one hiding in it

Suppose the sender receives three duplicate acknowledgements for the same data. It concludes that the segment following the one being acknowledged has been lost, and performs a fast retransmit [RFC 5681], resending that segment before its timer expires.

Count the arrows in scenario d. There are four acknowledgements carrying the value 100:

  • the first is the original, generated by segment 92 arriving in order;
  • the next three are duplicates, generated by segments 120, 135 and 141 arriving out of order.

So “three duplicate acknowledgements” means four acknowledgements in total. The book says as much later, in section 3.7.1: “one original ACK and then three duplicate ACKs”.

The ACK received event of the simplified sender gains an else branch, and that branch is the whole of fast retransmit:

event: ACK received, with ACK field value of y
    if (y > SendBase) {
        SendBase = y
        if (there are currently any not yet acknowledged segments)
            start timer
    }
    else {  /* a duplicate ACK for an already ACKed segment */
        increment number of duplicate ACKs received for y
        if (number of duplicate ACKs received for y == 3)
            /* TCP fast retransmit */
            resend segment with sequence number y
    }
    break;

Why three, and not one?

A single duplicate acknowledgement is weak evidence. Segments can arrive out of order simply because the network reordered them, which section 3.4.4 warned that a real network does. In that case the missing segment is not lost at all and will turn up shortly.

Retransmitting on the first duplicate would therefore cause a great many unnecessary retransmissions, which is exactly what congestion does not need. Waiting for three is a bet that mild reordering will not produce that many.

The book leaves the question as a homework problem rather than answering it, so this is the reasoning rather than a quotation.

So is TCP Go-Back-N or selective repeat?

Go-Back-N, selective repeat, or TCP?
Go-Back-N§3.4.3Selective repeat§3.4.4TCPthis section
Acknowledgements
Sender keeps
Receiver buffers out of order
Timers
On a timeout, resend
One acknowledgement lost among many
So which is it?

Cells marked ⓘ have a reason behind them — click to read it.

Every row is a real comparison from the book. Read the last one only after the others.

In plain words

Look at the row for a lost acknowledgement, because the book’s own example lives there.

Send segments 1 through N. All arrive in order and without error. Now lose only the acknowledgement for segment n, while the other N − 1 acknowledgements arrive before their timeouts.

  • Go-Back-N would retransmit segment n and n+1, n+2, … N.
  • TCP would retransmit at most one segment, n.
  • And TCP would not even retransmit n, if the acknowledgement for n+1 arrived before n’s timer expired.

Selective acknowledgement, and the last of the ambiguity

A proposed modification, the selective acknowledgement [RFC 2018], lets a TCP receiver acknowledge out-of-order segments selectively rather than only cumulatively acknowledging the last in-order segment.

Combined with selective retransmission — skipping segments the receiver has already reported having — TCP then looks a great deal like the generic selective repeat of section 3.4.4.

So the honest answer, and the book’s: TCP’s error recovery is best categorised as a hybrid of Go-Back-N and selective repeat. It is not a compromise anyone designed in one sitting; it is what thirty years of experience produced.

Check yourself

Check yourself

0 of 6 answered
  1. 1.predictIn the fast-retransmit run, how many acknowledgements carrying the value 100 does host A receive before it resends?

    Count them in the diagram, then read the rule carefully.

  2. 2.Why does a TCP receiver send a duplicate acknowledgement instead of saying "segment 100 is missing"?

  3. 3.predictSwitch to the run where a cumulative acknowledgement saves the day. ACK=100 is lost. Why is neither segment retransmitted?

  4. 4.How many retransmission timers does a TCP sender use, however many segments are outstanding?

  5. 5.After a timeout, TCP sets the next TimeoutInterval to double the previous one rather than recomputing it. Why?

  6. 6.Is TCP a Go-Back-N protocol or a selective-repeat protocol?

What to remember

  • TCP uses one timer, for the oldest unacknowledged segment. On a timeout it resends only the smallest-numbered unacknowledged segment, never the whole sender window.
  • Three duplicate acknowledgements — four in total, counting the original — trigger a fast retransmit before the timer expires. Three rather than one, because mild reordering would otherwise cause needless retransmissions.
  • TCP is a hybrid: cumulative acknowledgements like Go-Back-N, one-at-a-time retransmission and real buffering like selective repeat. With SACK it is closer still to selective repeat.