Two hosts exchange TCP segments one at a time — open a connection from either side, accept it, refuse it or reset it, send data and choose how much, lose or reorder segments on the way and retransmit them, and see which segment every ACK acknowledges.
TCP numbers every byte it sends, and every ACK names the next byte it expects, so each acknowledgment
can be traced back to the segments it covers. The simulator draws that tie between the two directions
of a connection: Host A sends from left to right, Host B from right to left, and every segment is one
you send and deliver by hand.
The simulator's layout
- The two hosts sit at the sides, each with its connection state, a column of actions and its
sequence variables. Each action button shows the segment it sends.
- The ladder in the middle is time running down. A segment is an arrow from the host that sent it
to the host that received it, and its card shows the fields that matter here: the flags,
seq, ack
and data-len, the number of data bytes it carries. - Clicking a card opens the whole header, the sequence numbers the segment occupies, and the
segments it acknowledges or is acknowledged by. The same links are drawn on the ladder as dotted
curves: green to the segments it acknowledges, purple to the one that acknowledges it.
- Reading the diagram, under the simulator, explains every line, dot and mark on the ladder.
- A segment on the wire has Deliver and Lose under its card, so segments can arrive in any
order, or not at all.
- Step and Prev move one event at a time. At the end of the list, Step delivers the oldest segment
still on the wire.
- Segments so far, under the diagram, lists every segment sent and what became of it.
Sending while stepped back into the past discards the events after that point and starts a new future
from there.
Opening a connection
Both hosts start CLOSED, and either one opens a connection with Initiate a connection, which sends
a SYN. The host that receives it chooses its answer:
- Accept the connection answers with a SYN-ACK.
- Refuse the connection answers with a reset, RST+ACK, which the connecting side reports as
connection refused. A real host refuses when no program listens on the port.
A host can answer only a segment that has arrived, so its buttons stay grey while the SYN is on the wire:
Step delivers it.
The three segments of the handshake each carry one number that matters:
- The SYN carries the client's initial sequence number, its ISS.
- The SYN-ACK carries the server's own ISS, and
ack = the client's ISS + 1: a SYN takes one sequence
number, although it carries no data. - The final ACK has
ack = the server's ISS + 1. It takes no sequence number, so the first data byte
still starts at the client's ISS + 1.
Each host picks a random ISS for every connection, as real stacks do, so that a segment from an old
connection or a stranger's guess does not fit the new one. Wireshark shows the same numbers relative,
counting from 0.
One connection between two fixed ports
The simulator holds one connection at a time, between Host A's port 51000 and Host B's port 8080, so
Initiate a connection stays grey until the current one has closed. A real client that opens a second
connection gets a new source port from its operating system, and the two connections are independent:
each has its own ISS and its own sequence numbers.
A SYN sent a second time, from the same port and with the same ISS, belongs to the same connection:
- Real TCP resends its SYN when no SYN-ACK arrives before a timer runs out; Retransmit does it
here.
- The receiver does not open a second connection. It recognises the ISS it already recorded, and
answers with its SYN-ACK again.
Sending data
Send data hands TCP one write: a block of bytes from the application, as many as the data-len
field under it says, 4000 unless you change it. Every data segment also carries an ACK for everything
its host has received.
- A write larger than one segment is cut up. A segment carries at most 1460 bytes here (the MSS), so
4000 bytes go out as 1460 + 1460 + 1080, one after another, without waiting for an ACK.
- PSH marks the last segment of a write. It tells the receiver that no more of the write is coming,
so it should pass the data to the application now. A write that fits in one segment therefore always
carries PSH, and a longer one carries it only on its last segment.
- The receive window limits a write. A host may have no more unacknowledged bytes in flight than
the window the other host advertised, 6000 here, so a second 4000-byte write waits for the first
one's ACK.
Acknowledge sends a pure ACK, with no data of its own. It lights up whenever a host owes one, and the
caption says why: data or a FIN has arrived, the SYN-ACK has completed the handshake, or a segment came
out of order or twice and the host repeats what it still expects.
Sequence and acknowledgment numbers
A segment's seq is the number of its first data byte, and its data occupies data-len numbers from
there. The receiver's ack is the number of the next byte it expects, which means it has every byte
before it.
data-len is not a field in the TCP header: the receiver works it out from the IP header's total length,
minus the IP and TCP headers.
- Host A, with ISS 1000, sends 100 bytes at seq 1001: they occupy 1001–1100, and its next segment
starts at 1101.
- Host B answers with ack 1101: everything up to 1100 arrived.
- A pure ACK takes no sequence number, so two ACKs in a row carry the same
seq, and nothing
acknowledges an ACK.
The host panels show the variables behind these numbers, as RFC 9293 names them: SND.UNA is the oldest
number sent and not yet acknowledged, SND.NXT the next number to send, and RCV.NXT the next number
expected, which is what the host's own ACKs say.
Cumulative acknowledgment
An ACK acknowledges every byte before its number, so a single ACK can cover several segments. The card
of an ACK lists the segments it acknowledges for the first time, and the details of a data segment name
the ACK that covered it.
Loss and retransmission
Lose, on a segment's card while it is on the wire, removes it. The receiver never sees it, and the sender keeps counting its
bytes as sent and unacknowledged:
- The segments after the lost one arrive out of order. The receiver holds them, and its ACK keeps
naming the first missing byte, so the sender gets duplicate ACKs.
- Retransmit resends the oldest unacknowledged segment. Real TCP resends it when a timer runs out,
or after the third duplicate ACK (fast retransmit).
The new segment's card says which one it resends, and selecting either draws an amber curve between
them.
- When the missing bytes arrive, the held ones join them, and the next ACK jumps past all of them.
The example A lost segment and its retransmission plays this through.
Closing a connection
Close the connection sends a FIN, which takes one sequence number, like the SYN. Each side closes its
own direction:
- The first host to close goes through
FIN_WAIT_1 and FIN_WAIT_2, and ends in TIME_WAIT once the
other side's FIN has arrived. - The other host goes to
CLOSE_WAIT, may still send data, and closes with its own FIN through
LAST_ACK. TIME_WAIT lasts twice the maximum segment lifetime, a minute or more, so that the last ACK can be
sent again if it was lost. End TIME_WAIT ends it at once.
Resetting a connection
Reset the connection ends it at once with a RST at the exact sequence number the peer expects. The
peer drops the connection without a reply, and neither side goes through TIME_WAIT.
The same button answers a segment that reaches a host with no connection, for example data still on
the wire when its connection was reset: the host owes a reset for it, and the button sends that one.
Simplifications in the simulator
- Segments move only when you deliver them: there are no timers, so nothing is retransmitted by itself.
- A receiver never answers unless replies are automatic is on, or you press one of its actions;
the button for the reply it owes is the one that is lit.
- A host with no connection accepts any SYN, and you decide whether it refuses; a real host decides by
whether a program listens on the port.
- The window is fixed at what each host last advertised: the application reads every byte at once.
- The checksum is not computed, and the only option is MSS on a SYN.
- Sequence numbers do not wrap around at 2³²: the random ISS is drawn low enough that they never reach it.