Learn Computer Networking

From “what happens after you press Enter?” down to sequence numbers and longest-prefix match. Every lesson starts from the problem the protocol solves, asks “why does this exist?”, distinguishes IPv4 from IPv6 and models from implementations, and most carry a simulator you can step through and break.

How the Internet Works

Press Enter on a URL and follow the request: layers, encapsulation, and an educational packet inspector.

Why? — What actually happens after you press Enter?

What Happens When You Press Enter
▶ interactive

Between pressing Enter on `https://engineer-atlas.dev` and seeing a page, a name becomes an address, an address becomes a path, a path carries a connection, the connection is secured, and only then does HTTP say a word — and each step has its own way of failing.

Follow a Web Request Through Every Layer
▶ interactive

The same `GET /` seen at fifteen rungs — browser, socket API, kernel, transport, IP, link, NIC, switch, router, NAT, ISP, internet, server network, server kernel, server process — with the exact state that changes at each one: which headers are added, which addresses are rewritten, and which are never touched.

The Layer Model: TCP/IP First, OSI as a Map
▶ interactive

Networking is stacked because each layer solves one problem for the layer above without knowing what it carries; the four-layer TCP/IP model describes what actually runs, the seven-layer OSI model is a vocabulary — and modern protocols such as TLS, QUIC and ARP refuse to sit in one box.

Encapsulation: Data, Segment, Packet, Frame
▶ interactive

Each layer wraps the one above in a header the layer below never reads: 100 bytes of HTTP become a 120-byte TCP segment, a 140-byte IP packet and a 154-byte Ethernet frame — and the 1500-byte MTU, the MSS derived from it, and path-MTU discovery decide how a large response is cut up so that nothing on the way has to fragment it.

Packet Inspector: Read a Frame Field by Field
▶ interactive

A single captured frame carrying an HTTP request, decoded layer by layer — Ethernet (src MAC, dst MAC, EtherType), IP (src, dst, TTL, protocol), TCP (ports, seq, ack, flags), HTTP — with, for every field, who wrote it, who reads it, and who is allowed to change it.

Ethernet, MAC & the Link Layer

Local delivery: frames, MAC addresses, switches, broadcast domains, ARP for IPv4 and neighbor discovery for IPv6; switches versus routers.

Why? — I know the IP address. How does the frame find the right cable?

IP, IPv4, IPv6, Subnets, NAT & Ports

Best-effort packet delivery, address structure, CIDR and subnetting, why IPv6 exists, NAT translation tables and what a port really is.

Why? — How does `192.168.1.42` know whether `10.0.0.7` is next door or across the world?

IP: Best-Effort Delivery Between Machines
▶ interactive

IP is the one protocol every device on the internet speaks: a source address, a destination address, a hop counter and a payload, forwarded hop by hop with no promise of delivery, order or uniqueness — a deliberately thin contract that leaves reliability to the ends and lets routers stay stateless.

IPv4: 32 Bits, Networks and Hosts

`192.168.1.42` is 32 bits split by a mask into a network part that routers care about and a host part that only the last router does; the private ranges, loopback, link-local and broadcast addresses are carved out of the same space, and the space ran out — which is why NAT and IPv6 exist.

IPv6: Not Just Bigger Addresses
▶ interactive

IPv6 gives every device a globally routable address and removes NAT as a necessity — but it also redesigns the header, replaces ARP and broadcast with ICMPv6 multicast, lets hosts configure themselves from router advertisements, forbids router fragmentation, and coexists with IPv4 through dual-stack and Happy Eyeballs rather than replacing it.

Subnetting: Splitting an Address Space
▶ interactive

`10.0.0.0/24` is 256 addresses with 254 usable; move the mask one bit right and it becomes two `/25`s of 128 — subnetting is prefix arithmetic, and it exists to bound broadcast domains, draw security boundaries and let routers aggregate many networks into one route.

Ports: Addressing a Process, Not a Machine
▶ interactive

An IP address reaches a machine; a 16-bit port reaches one program on it — `203.0.113.10:443` names the HTTPS listener. The 4-tuple of both addresses and both ports identifies a connection, which is why one server port serves thousands of clients and why a client that opens too many connections to one destination runs out of ports.

NAT: Many Private Hosts Behind One Public Address
▶ interactive

A NAT rewrites the private source `10.0.0.4:54001` to the public `203.0.113.7:62014` on the way out, records the mapping in a table, and reverses it on the way back — which lets a household or a data centre share one address, and which is the reason inbound connections, peer-to-peer, long-lived idle sockets and high connection rates all need special handling.

Routing

Routing tables, longest-prefix match, next hops, and how the internet is stitched together from autonomous systems with BGP.

Why? — A router sees a destination IP and has three matching routes. Which wins, and why?

DNS

From a name to an address: caches, recursive resolvers, root, TLD and authoritative servers, record types, TTLs — and a failure simulator.

Why? — Where does the IP for `engineer-atlas.dev` actually come from, and who is allowed to be wrong about it?

UDP

Datagrams over IP with no connection, no ordering and no retransmission — and why DNS, real-time media and QUIC choose exactly that.

Why? — Why would anyone want a transport that can lose your data?

TCP

A reliable ordered byte stream over an unreliable network: the handshake, sequence numbers, acknowledgments, loss recovery, flow control, congestion control, head-of-line blocking and the connection lifecycle.

Why? — How do you build a reliable stream out of packets that can be lost, duplicated and reordered?

TCP: A Reliable Ordered Byte Stream over an Unreliable Network

IP loses, duplicates, reorders and delays packets and says nothing about it; TCP turns that into a connection over which bytes arrive exactly once, in order, at a rate the receiver and the network can absorb — by numbering every byte, acknowledging what arrived, retransmitting what did not, and windowing what is in flight — and it hands the application a stream, not messages.

The Three-Way Handshake
▶ interactive

SYN, SYN-ACK, ACK: three segments in which each side proposes its initial sequence number and hears the other’s acknowledged, options are agreed, and the server moves the connection from a half-open queue to the accept queue — one full round trip before a single byte of data, which is the cost every short connection pays.

Sequence Numbers, ACKs and Reassembly
▶ interactive

Every byte in a TCP stream has a number; a segment carries the number of its first byte, an ACK carries the number of the next byte the receiver wants, and out-of-order segments wait in a reassembly buffer until the hole before them is filled — which is why numbers are byte offsets, why cumulative ACKs cannot describe a gap, and why SACK exists.

Packet Loss: Duplicate ACKs, Fast Retransmit and the RTO
▶ interactive

When a segment is lost, TCP learns it either from three duplicate ACKs (fast, one round trip) or from a retransmission timer (slow, at least 200 ms on Linux and doubling), retransmits, and — because loss is also read as congestion — cuts its sending rate; the application sees only a stall, and a loss rate of 1% can cost most of a link’s throughput.

Flow Control: The Receive Window
▶ interactive

The receiver tells the sender, in every ACK, how many more bytes it has room for; the sender never has more than that in flight; when the application stops reading, the buffer fills, the window goes to zero and the sender stops — so a slow consumer throttles a fast producer all the way back through the network, which is backpressure by design.

Congestion Control: Protecting the Network
▶ interactive

No router tells a sender how much capacity is left, so the sender probes: it keeps a congestion window that grows exponentially, then linearly, and shrinks sharply when loss or an ECN mark says a queue is full — the sawtooth that shares links fairly, and the mechanism that CUBIC and BBR each implement with different signals.

Head-of-Line Blocking
▶ interactive

Because TCP delivers bytes strictly in order, one lost segment holds back every byte behind it even when those bytes have already arrived — a property that HTTP/1.1 dodged with six parallel connections, that HTTP/2’s multiplexing made worse by putting every request on one stream, and that HTTP/3 addresses with QUIC’s independent streams, without eliminating ordering costs inside a stream or in the application.

The Connection Lifecycle: Close, Reset, TIME_WAIT, CLOSE_WAIT
▶ interactive

A TCP connection is a state machine on both ends: established by the handshake, torn down by a FIN in each direction, aborted by RST — and the side that closes first sits in TIME_WAIT for a minute holding the port pair, while a side that never calls close() sits in CLOSE_WAIT forever; these states explain ECONNRESET, ephemeral-port exhaustion, descriptor leaks, and why many short connections are expensive.

TLS & Certificates

TCP gives transport but not confidentiality or identity: the handshake, key agreement, certificates and the chain of trust.

Why? — How does my browser know it is talking to the real server, and not the coffee-shop Wi-Fi?

HTTP/1.1, HTTP/2 & HTTP/3

Requests, responses, headers and status codes; then the evolution from HTTP/1.1 through HTTP/2 multiplexing to HTTP/3 over QUIC; keep-alive and connection pooling.

Why? — Why did HTTP need three redesigns of its transport?

HTTP: Requests, Responses, Headers and Status Codes
▶ interactive

HTTP turns a byte stream into a request — method, path, headers, optional body — and a response — status code, headers, optional body; the method tells intermediaries whether a request is safe to retry and the status code tells the client what to do next.

The Lifecycle of One HTTP Request

A `fetch()` becomes an HTTP message inside TLS records inside TCP segments inside IP packets, crosses the network, is unwrapped in reverse on the server, handled, and returns the same way — and on a cold connection most of the time is round trips, not work.

HTTP/1.1: Persistent Connections and Their Limits

HTTP/1.1 keeps the TCP connection open between requests and delimits bodies with `Content-Length` or chunks, but it can only carry one response at a time per connection — so browsers open several connections per origin, and text parsing costs bytes and ambiguity on every message.

HTTP/2: Streams on One Connection
▶ interactive

HTTP/2 replaces text lines with binary frames tagged by stream id, so many requests and responses interleave on a single TCP connection with compressed headers — at the cost that one lost TCP segment now stalls every stream on that connection.

HTTP/3 and QUIC

HTTP/3 runs over QUIC, a UDP-based transport that folds TLS 1.3 into its handshake, gives each stream independent loss recovery, and survives a change of IP address — reducing, not eliminating, head-of-line blocking, at the price of userspace CPU and UDP-hostile networks.

HTTP/1.1 vs HTTP/2 vs HTTP/3
▶ interactive

Three versions with identical semantics and three different transports: sequential text over TCP, multiplexed frames over one TCP connection, and multiplexed streams over QUIC — each is the right choice for a different link and a different deployment.

Keep-Alive and Connection Reuse
▶ interactive

Reusing a connection skips the TCP and TLS handshakes and starts with a grown congestion window — but both ends, and every proxy between them, close idle connections on their own timers, and the race between a server closing and a client reusing produces the sporadic `ECONNRESET` every production system eventually meets.

Connection Pooling

Opening a connection costs handshakes, authentication and a cold congestion window, so clients keep a pool of open ones and hand them out per request — HTTP pools hold stateless connections any request can use, database pools hold connections that carry session state, and both fail the same way when the pool runs dry.

WebSockets, SSE & Polling

Getting data from the server without asking: polling, server-sent events and WebSockets compared on directionality, infrastructure, reconnection and scale.

Why? — The server has news. How does it tell a browser that only ever asks?

Proxies, Load Balancers & CDNs

Forward vs reverse proxies, L4 vs L7 balancing, health checks, and the networking view of a CDN: DNS, edge locations, caches and geographic distance.

Why? — When the client connects to "the server", what is it actually connected to?

Firewalls & VPNs

Rules that allow or deny traffic by address, port and protocol; stateful inspection; encrypted tunnels.

Why? — A ping fails but the service works. What is a firewall actually blocking?

Container & Kubernetes Networking

Network namespaces, virtual interfaces, bridges, and just enough Kubernetes to understand pod IPs, services, ingress and network policies.

Why? — Two containers on one host both bind port 80. How is that not a conflict?

Network Performance

RTT, bandwidth, loss, retransmission, connection and TLS setup, queueing — and why a request is slow while the server CPU sits idle.

Why? — The server is idle and the request still takes 800 ms. Where did the time go?

Network Debugging & Capstone

"Why can’t I connect?" as a layered procedure, the tools and which layer each answers, DNS/TCP/TLS/HTTP debugging — and the capstone: what happens when you visit `https://example.com`.

Why? — Connection timed out. Which of the nine layers failed?

Why Can’t I Connect?
▶ interactive

Every connection failure lives in exactly one layer, and the fastest way to find it is to bisect the ladder — DNS, route, host, port, handshake, TLS, HTTP, application — reading the failure signature at each step instead of guessing.

The Tools, and Which Layer Each One Answers
▶ interactive

ping, traceroute, dig, curl, ss, tcpdump, Wireshark, nc and openssl are not a list to memorise; each one asks a question at one layer and is blind to the others, so choosing the tool is choosing the layer you are testing.

ping: What an Echo Actually Proves

ping sends an ICMP echo request and reports whether a reply came back and how long it took; that answers "does this host respond to ICMP right now" and nothing else — a failed ping does not mean a service is down and a successful ping does not mean it is up.

traceroute: Discovering the Path Hop by Hop
▶ interactive

traceroute sends probes with TTL 1, 2, 3… and collects the ICMP Time Exceeded replies each router returns when it discards them, revealing the forward path one hop at a time — and the same mechanism is why the output is full of honest-looking lies.

DNS Debugging: Who Answered, and With What?

A name lookup can be answered by half a dozen different caches and resolvers before it reaches anyone authoritative, so the first question in every DNS problem is "which of them answered?" — and `dig` against a chosen server, `+trace` and the TTL in the answer will tell you.

TCP Debugging: Reading the Handshake on the Wire

"Connection times out" has exactly three wire signatures — SYN/SYN-ACK/ACK, SYN then RST, or SYN into silence — and one `ss` on the server plus one `tcpdump` on each end converts a vague timeout into a named cause: nothing listening, wrong bind address, dropped by a firewall, host down, backlog full or ephemeral ports exhausted.

TLS Debugging: Why the Certificate Is "Invalid"

"Certificate invalid" is the browser’s summary of six unrelated faults — wrong name, expired, missing intermediate, wrong clock, wrong certificate for the SNI, protocol or cipher mismatch — and `openssl s_client` plus `curl -v` name which one in a single line each.

HTTP Debugging: 502, 503 and 504 Are Different Failures

The three gateway errors usually describe three different upstream situations — 502 the backend answered wrongly or closed, 503 no backend was available, 504 the backend did not answer in time — and the debugging procedure is to find which hop generated the status, correlate with that hop’s upstream logs and health state, and check that the timeout ladder is ordered.

Capstone: What Happens When You Visit https://example.com
▶ interactive

The canonical networking interview question is a test of whether you can tell the story at the right altitude — nine steps in a minute, twelve layers on request, and at every layer the mechanism, the state that changes, and the failure you would name.

Packet Lab

Follow one packet hop by hop and inspect its state, then inject failures — loss, latency, DNS outage, expired certificate, blocked port — and predict the behaviour.

Why? — What changes in the packet at each hop, and what happens when a hop fails?

OS + Networking Together

Follow `send()` through the socket API, the kernel, the transport stack and the NIC to a server that wakes up in `recv()`; build a tiny server from blocking to event-driven; buffers, backpressure, zero-copy and a combined failure simulator.

Why? — What actually happens between writing `send()` and another machine’s process waking up?

Follow send() Through the OS to recv()
OS + Net▶ interactive

Between `send()` returning in one process and `recv()` returning in another there are two kernels, two NICs, three copies, a congestion gate, a routing decision and at least one context switch — and every one of them is a place where bytes wait.

Build a Tiny Server: V0 to V5
OS + Net▶ interactive

Six versions of the same server, each one born from the specific failure of the previous one: a single request, a blocking loop, a thread per client, a pool, non-blocking sockets, and finally an event loop.

The Blocking Server
OS + Net

accept → read → process → write → next: the simplest correct server, and the clearest demonstration that a blocking call parks the whole program on one client’s behaviour.

Thread per Connection
OS + Net

Give every client its own thread and let the scheduler interleave them: the code stays sequential and the OS supplies the concurrency — until the number of threads becomes the workload.

The Thread Pool Server
OS + Net

A fixed set of workers pulling connections from a bounded queue: thread cost becomes a constant, overload becomes a queue length you can see, and the slow client returns as "one slow request occupies a worker".

The Event-Driven Server
OS + Net

One thread, many non-blocking sockets, and a kernel API that says which ones are ready: the server sleeps until something happens and then does exactly the work that is possible — as long as nothing in it ever blocks.

C10K: Ten Thousand Connections, Then a Million
OS + Net▶ interactive

The limits are concrete and countable: threads, descriptors, kernel socket memory, wake-up cost, ephemeral ports, middlebox state — and each has a mechanism that moved it, which is why the number went from 10K to 10M without the laws of physics changing.

The Buffer Chain
OS + Net▶ interactive

Application buffer → socket send buffer → device queue → wire → NIC ring → socket receive buffer → application: a chain of bounded queues in which every full buffer pushes back on the one above, sized by bandwidth × delay and dangerous when oversized.

What Happens When the Receiver Is Slow
OS + Net▶ interactive

A fast sender and a slow reader: the receive buffer fills, the window closes, the send buffer fills, and the sender’s `write()` blocks, returns EAGAIN, returns false, or awaits — depending only on which I/O model it chose. Buffer in user space instead and it fails by running out of memory.

Zero-Copy: Serving a File Without Touching It
OS + Net▶ interactive

Serving a file the naive way copies it four times and crosses the user/kernel boundary four times; `sendfile`, `splice`, scatter-gather DMA and, at the extreme, kernel bypass remove the copies the CPU does not need to make — until TLS puts one back.

Memory Mapping, the Page Cache and Network I/O
OS + Net

High-throughput systems are built by letting the page cache be the shared buffer between disk, process and NIC, and by batching every crossing of the user/kernel boundary: Kafka’s log, a database’s buffer pool, `writev`, and io_uring.

Combined Failure Simulator: Break a Layer, Watch It Propagate
OS + Net▶ interactive

Application → kernel → network → remote: exhaust descriptors, fill a buffer, block a thread, drop packets, add latency, kill the process, restart the server — and follow each failure across the layers to the symptom the user sees and the tool that proves it.

Capstone: Three Seconds from Warsaw
OS + Net▶ interactive

A user in Warsaw opens your application hosted in another region and the page takes three seconds: enumerate every layer where the time could be, assign each to the domain that explains it, put a typical cost and a measurement next to each, and bisect.