Zoom-in: TCP

Every HTTP request runs on TCP. But before the first byte of real data crosses the wire, three packets are exchanged carrying no payload at all. That's not wasted overhead — it's the price of a reliable channel on a network that guarantees nothing.
Zoom in.
Layer 1 — The problem: the Internet doesn't guarantee delivery
The Internet is a best-effort network. Each router tries to forward packets — no guarantees, no confirmations.
graph LR
C["💻 Client"] -->|"packet 1"| I["🌐 Internet"]
C -->|"packet 2"| I
C -->|"packet 3"| I
I -->|"packet 1 ✓"| S["🖥️ Server"]
I -->|"packet 3 ✓"| S
I -.->|"packet 2 ✗ dropped"| S
style C fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
style I fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
style S fill:#1a3a2a,stroke:#22c55e,color:#86efac
Packets can be lost, arrive out of order, or be duplicated. IP has no mechanism to handle any of this. The layer above must.
Layer 2 — 3-way handshake: opening a connection
Before any data is sent, TCP requires both sides to establish a connection in three steps.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: SYN (seq=100)
Note right of C: "I want to connect.\nMy sequence number is 100."
S-->>C: SYN-ACK (seq=300, ack=101)
Note left of S: "OK. My sequence is 300.\nI received your seq 100."
C->>S: ACK (ack=301)
Note right of C: "I received your seq 300.\nConnection ready."
Each side picks a random sequence number at the start. That number is the foundation for reordering packets and detecting loss. Why 3 steps and not 2? Because both directions need to be confirmed — the client needs to know the server is listening, and the server needs to know the client received the response.
Layer 3 — Data transfer: sequence numbers and ACK
Every byte of data is numbered by sequence number. The receiver confirms receipt with ACK.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: DATA (seq=101, bytes 1-1000)
C->>S: DATA (seq=1101, bytes 1001-2000)
S-->>C: ACK (ack=2101) — "received up to byte 2100"
C->>S: DATA (seq=2101, bytes 2001-3000)
Note over C,S: ⚡ Packet dropped in transit
Note over S: timeout — nothing received
S-->>C: ACK (ack=2101) — "still waiting from byte 2101"
C->>S: DATA (seq=2101) — retransmit
This is selective retransmission — only the lost packet is resent, not everything from the beginning. TCP also implements flow control (receiver window) and congestion control to avoid saturating the network.
Layer 4 — 4-way FIN: closing the connection
Closing requires 4 steps because the two directions are independent — each side declares it's done sending on its own.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: FIN
Note right of C: "I'm done, won't send more"
S-->>C: ACK
Note left of S: "Got it"
Note over S: Server may still be sending data
S-->>C: FIN
Note left of S: "I'm done too"
C->>S: ACK
Note right of C: "Got it. Wait 2×MSL then close."
Note over C: TIME_WAIT (2 × MSL ≈ 60-120s)
TIME_WAIT is the state the client holds after sending the final ACK — to ensure that ACK actually reached the server. If the server didn't receive it, it will retransmit its FIN and the client needs to still be alive to respond. TIME_WAIT also prevents old sequence numbers from a previous connection from bleeding into a new one.
Full picture
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: 🤝 Open connection
C->>S: SYN (seq=100)
S-->>C: SYN-ACK (seq=300, ack=101)
C->>S: ACK (ack=301)
Note over C,S: 📦 Transfer data
C->>S: DATA (seq=101...)
S-->>C: ACK
S-->>C: DATA (seq=301...)
C->>S: ACK
Note over C,S: 👋 Close connection
C->>S: FIN
S-->>C: ACK
S-->>C: FIN
C->>S: ACK
Note over C: TIME_WAIT (60-120s)
Takeaway
TCP exists because the Internet guarantees nothing. The handshake costs one round-trip before any data flows — that's the fixed price of every new TCP connection. HTTP/2 reduces this cost with multiplexing. HTTP/3 goes further by replacing TCP entirely with QUIC over UDP, handling reliability at the application layer.
When debugging unexpectedly high latency: check how many handshakes are happening. Keep-alive and connection pooling exist for exactly this reason — opening a new TCP connection is not free.
This post was assisted by Amy 🌸 - AI Assistant. Content has been reviewed by the author.
Related Posts
Zoom-in: Load Balancer
One domain, millions of requests per day. A load balancer doesn't just split traffic — it decides routing, health checking, and session management for the entire system.
Zoom-in: DNS
Type 'google.com', press Enter. Your machine doesn't understand domain names — it only understands IP addresses. Between those two is a four-layer distributed lookup system.
Zoom-in: HTTP
Every web app starts from a simple model: client asks, server answers. HTTP is the language of that conversation — but five layers of infrastructure make it work.