Skip to main content

Reliable Data Transfer

The network layer below TCP is unreliable: packets can be lost, corrupted, or reordered. TCP builds a reliable byte stream on top of it using three tools - sequence numbers, acknowledgements (ACKs), and retransmission on timeout. The story of how to do this efficiently is a short progression.

Stop-and-wait

The simplest correct protocol: send one packet, then wait for its ACK before sending the next. If the ACK does not arrive before a timeout, resend the packet.

It is easy to reason about but painfully slow: the link sits idle for a whole round-trip after every single packet. With a fast link and a long delay, you use almost none of the available bandwidth.

Pipelining

The fix is to stop waiting: keep several packets in flight at once, before any of them are acked. The number allowed outstanding is the window. A bigger window fills a high-latency link instead of leaving it idle.

Pipelining raises a question loss did not before: when packet 3 of an in-flight batch is lost, what do you resend? Two answers define two protocols.

Go-Back-N

Go-Back-N keeps it simple: the receiver only accepts packets in order and acks the highest in-order packet it has. When the sender times out on the oldest un-acked packet, it resends that packet and every packet after it in the window - it "goes back N."

Simple sender and receiver, at the cost of re-sending packets that may already have arrived.

Worked example: Go-Back-N with a window of 4

Say the sender uses sequence numbers 0-7 and a window size of 4, and has already sent packets 0, 1, 2, 3 (all in flight, none acked yet):

  • The receiver gets 0 and 1 in order, delivers them, and acks each ("ACK 0", "ACK 1"). The sender's window slides forward: base moves from 0 to 2, so packets 4 and 5 can now go out too.
  • Packet 2 is lost in transit. Packet 3 arrives, but the receiver is strictly in-order: it discards packet 3 (even though it arrived intact) because packet 2 has not shown up yet, and it just re-acks "ACK 1" again (a duplicate ack for the last in-order packet it has).
  • The sender's timer for packet 2 (the oldest un-acked packet, base = 2) eventually fires. Go-Back-N resends everything from base onward that is still in the window: packets 2, 3, 4, 5 - even though 4 and 5, and even 3, may have already arrived safely the first time.

That last step is the whole trade-off: one lost packet in a window of 4 costs 4 retransmissions, not 1. A bigger window makes better use of the link when nothing is lost, but makes every loss more expensive to recover from.

Selective repeat

Selective repeat is the smarter cousin: the receiver buffers out-of-order packets and acks each one individually, so the sender retransmits only the packets that were actually lost. Less wasted bandwidth, more bookkeeping on both ends. TCP's behaviour sits close to this end of the spectrum.

Try it

The window below slides over a row of packets. Set the window size (a size of 1 is stop-and-wait). Click any packet to mark it lost, then step to watch the timeout and the Go-Back-N retransmission of the whole window.

Go-Back-N (N=3)
sentackedlostin window
Send packet 0
event 0 / 11
tip

Set the window to 1 and watch it become pure stop-and-wait: one send, one ACK, repeat. Widen it and the same loss now forces a bigger retransmission - the trade-off Go-Back-N makes for its simplicity.

Gotcha

Waiting for the retransmission timeout is often too slow for a real connection - by the time it fires, the link has sat partially idle for a full RTO. TCP does not actually wait for a timeout in the common case: when the receiver gets an out-of-order packet, it immediately re-acks the last in-order byte it has, and three duplicate ACKs in a row tell the sender a packet is almost certainly lost - triggering a fast retransmit well before the timer would have fired. A production TCP stack (or a naive reimplementation) that only retransmits on timeout, and never watches for duplicate ACKs, pays for every single loss with a multi-hundred-millisecond stall instead of a near-instant resend.