The TCP/IP model is the foundation of all modern internet communication. Understanding it makes you a better debugger, a more thoughtful architect, and a more confident engineer when things go wrong at 3 am.

The Four Layers

Unlike the OSI model's seven layers (which is a conceptual reference model), TCP/IP condenses the stack into four practical layers, each with a clear responsibility:

  1. Application Layer — The protocols your applications speak: HTTP/HTTPS, DNS, SMTP, FTP, WebSocket.
  2. Transport Layer — Manages end-to-end communication. Two protocols live here: TCP (reliable) and UDP (fast).
  3. Internet Layer — Handles logical addressing and routing. IP (v4 and v6), ICMP, and ARP operate here.
  4. Link Layer — The physical transmission medium: Ethernet frames, Wi-Fi (802.11), and MAC addressing.

When you visit a website, data travels down the stack on the sender side (each layer adding a header) and back up the stack on the receiver side (each layer stripping its header). This is called encapsulation and decapsulation.

The Three-Way Handshake

Before any data can flow over a TCP connection, both sides must agree to communicate. This is called the three-way handshake and it establishes sequence numbers that guarantee in-order delivery.

CONNECTION SEQUENCE
Client ──SYN (seq=x) ────────────────→ Server Client ←─ SYN-ACK (seq=y, ack=x+1) ── Server Client ──ACK (ack=y+1) ─────────────→ Server ✓ Connection established Data can now flow in both directions.

The handshake takes at minimum one round-trip time (RTT) before the first byte of application data can be sent. This is a key reason HTTPS connections feel slower on high-latency links — TLS adds another 1–2 RTTs on top.

TCP vs UDP: The Core Trade-off

TCP provides reliability guarantees through acknowledgements, retransmission of lost packets, and flow control. UDP provides none of these — it simply fires packets and hopes they arrive.

That sounds like UDP loses every time, but the opposite is true for latency-sensitive applications. In live video streaming, a dropped packet is better than a delayed one — receiving a video frame 500ms late is far worse than skipping it entirely. Online gaming, DNS lookups, and VoIP all use UDP for this reason.

PYTHON
import socket # TCP client — connection-oriented s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('example.com', 80)) s.sendall(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n') # UDP client — connectionless (fire and forget) u = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) u.sendto(b'ping', ('8.8.8.8', 53))

HTTP/2 and Multiplexing

HTTP/1.1 opens a separate TCP connection for each resource, or queues requests on a single connection (head-of-line blocking). HTTP/2 introduces multiplexing — many logical streams over a single TCP connection — dramatically reducing connection overhead.

Every web request you make triggers this entire stack — DNS lookup, TCP handshake, TLS negotiation, HTTP request/response — in under 100ms on a good connection. That is a remarkable feat of engineering.