Skip to content
Cumulative ACK & Retransmission Queue
step 1/5

Reading — step 1 of 5

Read

~2 min readReliability & Flow Control

Cumulative ACK & the retransmission queue

When a TCP sender transmits a segment carrying bytes [seq, seq+len), it doesn't get to forget them. It must keep that data around until the receiver acknowledges it. That's the retransmission queue — and it's why a TCP sender's memory grows with bandwidth-delay product, not application demand.

What "cumulative" means

A TCP ACK field carries one number: the next sequence number the receiver expects. An ACK of N acknowledges all bytes with sequence numbers strictly less than Nevery byte below N, including ones from earlier segments (RFC 793 §3.3). And that acknowledgment is a promise about custody, not delivery: RFC 793 (§2.6) is explicit that an ACK means the receiving TCP has taken responsibility for the bytes, not that the application has read them yet.

Why cumulative

The design choice means even if some ACKs are lost in the network, a later ACK acknowledges everything below it. The receiver never has to retransmit ACKs.

It also means one piece of data can be partially acked: if you sent [0, 100) and an ACK of 50 arrives, the receiver got the first 50 bytes; the segment now becomes [50, 100) in your queue.

The retransmission queue in practice

A TCP sender keeps an ordered list of in-flight intervals. When an ACK arrives with value A:

  1. Drop any interval where end <= A (fully acked).
  2. For an interval where seq < A < end: trim the front to [A, end).
  3. The retransmission timer resets only for intervals that remain.

When the timer fires, the oldest outstanding segment is retransmitted (RFC 6298). Modern TCP also uses fast retransmit — three duplicate ACKs for the same value mean a segment was probably lost, so we retransmit immediately rather than waiting for the RTO.

SACK: a refinement, not a replacement

Modern stacks negotiate Selective ACK (RFC 2018) at handshake time. SACK adds extra information ("I also have [200, 300)") on top of the cumulative ACK; it doesn't replace it. Your build will implement the pure cumulative case — the SACK extension is layered on top.

In your build

You'll maintain a list of outstanding intervals and process SEND <seq> <len>, ACK <ack_no>, and QUEUE events. Pay attention to the partial-ack case — it's a common bug to drop the whole segment when only its leading edge was acked.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…