TCP: Reliable Delivery
Imagine sending a jigsaw puzzle to a friend through the post. You cannot fit the whole puzzle in one envelope, so you split it into numbered pieces and send each piece in its own envelope. Your friend checks the numbers, puts the pieces in order, and tells you which ones arrived safely. If any go missing, you send them again. That is TCP.
What Is TCP?
TCP (Transmission Control Protocol) sits between the application layer (HTTP, DNS) and the network layer (IP). It turns unreliable, unordered network delivery into a reliable, ordered byte stream.
TCP gives you four guarantees:
- Reliable delivery -- lost segments are detected and retransmitted.
- Ordered delivery -- segments arrive in the correct sequence.
- Flow control -- the receiver tells the sender how much room it has.
- Congestion control -- the sender slows down when the network is busy.
Without TCP, applications would have to handle all of this themselves. With TCP, they just send and receive bytes.
The Three-Way Handshake
Before two computers can exchange data, they need to agree to start a conversation. TCP uses a three-way handshake:
Client Server
| |
|--- SYN (seq=0) ------------>| "Hey, want to talk?"
| |
|<-- SYN+ACK (seq=0, ack=1) --| "Sure, let's talk!"
| |
|--- ACK (ack=1) ------------>| "Great, we're connected!"
| |
- SYN -- "synchronise" -- the client proposes a starting sequence number.
- SYN+ACK -- the server agrees and proposes its own sequence number.
- ACK -- the client acknowledges. Both sides are now ESTABLISHED.
In PyOS:
Sequence Numbers and Acknowledgements
Every byte of data has a sequence number. When the receiver gets data, it sends back an ACK with the next sequence number it expects. This is how the sender knows what arrived safely.
Sender Receiver
| |
|--- data (seq=1, 5 bytes) ---->|
| |
|<-- ACK (ack=6) ---------------| "Got it, send byte 6 next"
| |
If the sender does not get an ACK within a timeout, it retransmits the data.
Flow Control: The Sliding Window
The receiver advertises a receive window -- the number of segments it can accept right now. The sender must not send more than this window allows.
Think of it like a mailbox with limited space. If the mailbox is full, the postman waits until you empty it before delivering more.
Congestion Control: Don't Flood the Network
Imagine you're pouring water into a cup. You start with a tiny trickle to make sure you don't spill. As you see it's going fine, you pour a little more. If it overflows, you slow way down. That's how congestion control works!
Even if the receiver has room, the network might be busy. TCP uses congestion control to avoid overwhelming the network:
Slow Start
Start slow and ramp up quickly:
- Begin with a congestion window (cwnd) of 1 segment.
- For each ACK received, increase cwnd by 1.
- This means cwnd doubles every round trip -- exponential growth!
- Keep growing until cwnd reaches the slow-start threshold (ssthresh).
Congestion Avoidance (AIMD)
Once cwnd reaches ssthresh, switch to cautious growth:
- Additive Increase -- increase cwnd by 1 per round trip (linear growth).
- Multiplicative Decrease -- on timeout, set ssthresh = cwnd / 2 and reset cwnd to 1.
This "AIMD" pattern creates a sawtooth shape: cwnd grows slowly, drops sharply on loss, then grows again.
In PyOS, you can see the congestion state:
The Effective Window
The sender's actual limit is the effective window: the smaller of cwnd and the receiver's advertised window.
This ensures the sender respects both the receiver's capacity and the network's capacity.
Retransmission
If a segment is not acknowledged within a timeout period, the sender assumes it was lost and retransmits:
- Start a timer when a segment is sent.
- If the timer expires before an ACK arrives, retransmit the oldest unacknowledged segment.
- Apply multiplicative decrease: ssthresh = cwnd / 2, cwnd = 1.
In PyOS, retransmission is driven by kernel.tick(). The default timeout is 10 ticks.
Graceful Close
When both sides are done, they close the connection with a four-way close:
Client Server
| |
|--- FIN ---------------------->| "I'm done sending"
|<-- ACK ----------------------| "OK, I heard you"
| |
|<-- FIN ----------------------| "I'm done too"
|--- ACK ---------------------->| "OK, goodbye"
| |
After the final ACK, the connection enters TIME_WAIT briefly to handle any delayed segments, then closes.
TCP State Machine
A TCP connection moves through 11 states:
| State | Meaning |
|---|---|
| CLOSED | No connection |
| LISTEN | Waiting for incoming SYN |
| SYN_SENT | SYN sent, waiting for SYN+ACK |
| SYN_RECEIVED | SYN received, SYN+ACK sent |
| ESTABLISHED | Connected, data flows |
| FIN_WAIT_1 | FIN sent, waiting for ACK |
| FIN_WAIT_2 | FIN acknowledged, waiting for peer's FIN |
| TIME_WAIT | Both FINs acknowledged, waiting before close |
| CLOSE_WAIT | Peer's FIN received, waiting to close |
| LAST_ACK | FIN sent, waiting for final ACK |
| CLOSING | Both sides sent FIN simultaneously |
Try It Yourself
Boot PyOS and run the interactive lesson:
Or experiment manually:
tcp listen 80 # Server listens on port 80
tcp connect 5000 80 # Client connects from port 5000
tcp send 2 "Hello!" # Send data on connection 2
tcp recv 3 # Receive data on connection 3
tcp info 2 # See congestion/flow control state
tcp close 2 # Graceful close
tcp list # See all connections
Or run the built-in demo:
Where to Go Next
- Interrupts and Timers -- How hardware events get the CPU's attention
- Devices and Networking -- Sockets, DNS, and HTTP built on top of TCP
- The Shell -- The
tcpshell commands for hands-on experimentation
Key Terms
| Term | Definition |
|---|---|
| TCP | Transmission Control Protocol -- provides reliable, ordered delivery over an unreliable network |
| Three-way handshake | SYN → SYN-ACK → ACK sequence that opens a connection |
| Sequence number | A counter that numbers each byte (or segment) so the receiver can reassemble them in order |
| ACK | Acknowledgement -- the receiver confirms which bytes it has received |
| Flow control | The receiver tells the sender how much room it has (window size), preventing overflow |
| Congestion control | Adjusting send rate based on network conditions to avoid overloading routers |
| Slow start | Start sending slowly and double the window each round trip until congestion is detected |
| AIMD | Additive Increase / Multiplicative Decrease -- grow the window slowly, cut it in half on loss |
| Retransmission | Resending a segment that was lost or not acknowledged in time |
| FIN | A flag that says "I'm done sending data" -- used to close a connection gracefully |