Guide
TCP/IP fundamentals explained
When you load a webpage, your browser does not send "HTTP" across the internet — it sends IP packets wrapped in TCP segments that carry HTTP as payload. The TCP/IP protocol suite is the plumbing every web request, API call, database connection, and blockchain RPC rides on. You can ship features for years without thinking about it — until a connection hangs, a firewall blocks a port, or a VPN path silently drops large packets. This guide walks through the layered model developers actually need, how addressing and routing work, the difference between TCP and UDP, and a practical checklist for debugging network failures — building on DNS resolution and leading into TLS and HTTP/2 and HTTP/3.
The layered model (without memorizing OSI)
Textbooks show seven OSI layers; production debugging uses a simpler four-layer view that maps directly to tools you already have:
- Link layer — Ethernet or Wi-Fi frames on your local network. Your laptop talks to your router via MAC addresses. Problems here look like "Wi-Fi connected but no internet."
- Internet layer (IP) — packets routed across networks using IP
addresses. IPv4 (
203.0.113.10) and IPv6 (2001:db8::1) are the addressing schemes. Routing tables and BGP decide which path packets take between continents. - Transport layer (TCP or UDP) — end-to-end delivery between processes on two hosts, identified by port numbers. TCP provides reliable, ordered byte streams. UDP sends discrete datagrams with no delivery guarantee.
- Application layer — HTTP, TLS, SSH, SMTP, and your game netcode protocols. These ride inside TCP or UDP payloads.
When debugging, work bottom up: can you reach the IP? Does the port accept connections? Does TLS negotiate? Only then inspect HTTP status codes. Skipping layers leads to chasing application bugs that are really firewall or routing problems.
IP: addressing, packets, and routing
An IP packet has a source address, destination address, a time-to-live (TTL) hop counter, and a payload. Routers along the path read the destination IP, consult their routing table, and forward toward the next hop. No router guarantees end-to-end delivery — that is the transport layer's job.
IPv4 vs IPv6 in practice
IPv4 uses 32-bit addresses (about 4 billion theoretical hosts; far fewer routable today due to exhaustion). IPv6 uses 128-bit addresses and simplifies header processing. Most production sites serve both: A records for IPv4 and AAAA records for IPv6. A common outage pattern is a correct A record but a broken AAAA record — IPv6-first clients fail while IPv4 works fine. Test both when you change DNS.
Private vs public addresses
RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12,
192.168.0.0/16) are not routable on the public internet. Your home
router assigns private IPs to laptops and phones; NAT (below)
translates outbound traffic to the router's public IP. Cloud VPCs use the same pattern:
your application servers often have private IPs, with a
load balancer holding
the public address.
ICMP: ping and traceroute
ICMP is a control protocol at the IP layer — not TCP or UDP. The
familiar ping command sends ICMP echo requests; traceroute
(or tracert on Windows) maps hops by manipulating TTL. Ping success
proves reachability at the IP layer but does not prove a TCP port is open —
firewalls often block ICMP while allowing HTTPS on port 443.
TCP vs UDP: reliability vs speed
| Property | TCP | UDP |
|---|---|---|
| Delivery | Guaranteed, retransmits lost segments | Best-effort, no retransmission |
| Ordering | Bytes arrive in send order | No ordering guarantee |
| Connection | Connection-oriented (handshake) | Connectionless |
| Overhead | Higher (headers, ACKs, congestion control) | Lower per packet |
| Typical uses | HTTPS, APIs, databases, email | DNS, video streaming, gaming, QUIC base |
HTTPS uses TCP (or QUIC, which reimplements reliability over UDP for HTTP/3). Real-time multiplayer games often use UDP for position updates where a late packet is worthless — the next frame supersedes it. DNS queries use UDP on port 53 for speed, falling back to TCP for large responses. Choosing the wrong transport for your workload is a classic architecture mistake: TCP's head-of-line blocking hurts latency-sensitive streams; UDP's unreliability breaks file transfers unless you add your own retry logic.
The TCP three-way handshake
Before any HTTP request, client and server establish a TCP connection with a three-way handshake:
- SYN — client sends a segment with the SYN flag set, proposing an initial sequence number.
- SYN-ACK — server acknowledges the client's SYN and sends its own SYN with its initial sequence number.
- ACK — client acknowledges the server's SYN. Both sides now agree
on sequence numbers and the connection enters the
ESTABLISHEDstate.
Each step costs at least one network round trip. On a 100 ms RTT mobile link, the handshake alone adds 100–300 ms before TLS even starts — which is why HTTP/3 over QUIC merges transport and encryption setup. A connection that stalls at SYN with no SYN-ACK usually means a firewall drop, wrong IP, or the server process is not listening on that port.
Connection teardown and TIME_WAIT
Closing a TCP connection uses a four-way FIN/ACK exchange. The side that initiates
close enters TIME_WAIT for 30–120 seconds to catch stray late packets.
High-churn servers that open thousands of short-lived connections to the same
destination can exhaust ephemeral ports — a problem load balancers and connection
pooling solve by reusing keep-alive connections.
Ports, sockets, and listening services
An IP address identifies a host; a port identifies a process on that host. A socket is the combination of protocol + local IP + local port + remote IP + remote port. Well-known ports include 80 (HTTP), 443 (HTTPS), 22 (SSH), and 5432 (PostgreSQL). Ephemeral ports (typically 32768–60999 on Linux) are assigned to outbound client connections.
A server binds to a port and listens for incoming connections. Your nginx reverse proxy listens on 443; Node.js behind it might listen on 127.0.0.1:3847. If two processes try to bind the same address:port, the second fails with "address already in use."
Checking what is listening
# Linux — show listening TCP ports
ss -tlnp
# Test remote port reachability (not a full HTTP check)
nc -zv example.com 443
# See established connections to your API
ss -tn state established '( dport = :443 )'
From outside your network, nc or an online port checker confirms whether
the path to port 443 is open. From inside a VPC, security groups may allow internal
traffic while blocking the public internet — always test from the client's perspective.
NAT: how private networks reach the internet
Network Address Translation rewrites source IP and port on outbound
packets so many private devices share one public IP. Your home router's NAT table
maps 192.168.1.42:54321 to 203.0.113.5:60001. Inbound
connections to arbitrary ports are dropped unless you configure port forwarding.
NAT implications for developers:
- WebRTC and P2P need STUN/TURN servers because two NATed clients cannot open direct TCP connections without coordination.
- Webhook receivers on your laptop require tunneling tools (ngrok, Cloudflare Tunnel) — your NAT blocks inbound port 443.
- Long-lived TCP connections through carrier-grade NAT may be reset after idle timeouts; keep-alive packets prevent silent drops.
- Source IP logging behind a
load balancer shows the
balancer's IP unless you forward
X-Forwarded-Foror use PROXY protocol.
MTU, fragmentation, and black holes
The Maximum Transmission Unit (MTU) is the largest IP packet a link can carry without fragmentation. Ethernet defaults to 1500 bytes. When a packet exceeds the path MTU, routers either fragment it (IPv4) or drop it and send ICMP "fragmentation needed" (IPv4 with DF bit, IPv6).
A PMTUD black hole occurs when intermediate firewalls block ICMP but
still drop oversized packets. Symptoms: small requests succeed, large responses hang
forever. VPN tunnels often lower effective MTU to 1400 or below. Fixes include lowering
TCP MSS via iptables -j TCPMSS --clamp-mss-to-pmtu, setting MTU on the
VPN interface, or enabling TCP MTU probing. If SSH works but HTTPS hangs on large
pages, suspect MTU before blaming application code.
TCP congestion control and why latency spikes
TCP is fair and adaptive. Algorithms like Cubic (default on Linux) and BBR probe available bandwidth by increasing the congestion window, then back off when packets drop. On lossy Wi-Fi, aggressive backoff can crater throughput. On a saturated link, a large file download competes with your API calls on the same TCP connection pool.
For web performance, this is why:
- HTTP keep-alive reuses connections instead of repeating handshakes.
- HTTP/2 multiplexing shares one TCP connection across many requests — but also shares congestion state.
- Edge CDNs terminate TCP close to users, shortening the lossy segment of the path.
Persistent high latency with zero packet loss often points to bufferbloat — oversized router queues — rather than raw bandwidth limits.
From TCP connection to your application
Putting the stack together for a typical HTTPS page load:
- DNS resolves
example.comto an IP (see our DNS guide). - TCP handshake to port 443 on that IP.
- TLS handshake negotiates encryption and verifies the certificate.
- HTTP request sent as encrypted bytes inside TCP segments.
- Response streamed back in segments, reassembled in order by TCP.
A failure at step 2 looks like "connection timed out." At step 3, "SSL handshake failed." At step 4, HTTP 404 or 500. Matching symptoms to layers cuts debugging time dramatically.
Production debugging checklist
- Confirm DNS —
dig +short example.com AandAAAA. Compare against expected origin or CDN IP. - Test IP reachability —
pingortracerouteto the resolved IP. Note which hop latency jumps. - Test port open —
nc -zv IP 443orcurl -v --connect-timeout 5 https://example.com/and read whether failure is before or after "Connected." - Inspect TLS separately —
openssl s_client -connect example.com:443 -servername example.comshows certificate chain without HTTP noise. - Check local listeners — on the server,
ss -tlnp | grep 443confirms the process is bound. - Review firewall rules — cloud security groups,
ufw, and iptables often allow 22 but forget 443 on new instances. - Test both IPv4 and IPv6 —
curl -4vscurl -6isolates AAAA misconfiguration. - Suspect MTU on VPN paths — if small payloads work and large ones hang, lower interface MTU or enable MSS clamping.
- Capture packets when stuck —
tcpdump -i any host example.com and port 443on the server shows whether SYNs arrive and SYN-ACKs leave. - Log connection errors with context — errno, remote IP, port, and whether the failure was timeout, reset (RST), or refused.
Key takeaways
- TCP/IP is a layered stack — debug from IP reachability up, not from HTTP status codes down.
- TCP provides reliable ordered byte streams; UDP trades guarantees for lower latency — choose intentionally.
- The three-way handshake and TLS add round trips before your first byte of application data.
- Ports route traffic to processes; NAT and firewalls are the usual reason inbound connections fail.
- MTU black holes cause selective hangs on large transfers — test with VPN and tunneled paths in mind.
- Every HTTPS request depends on DNS, TCP, and TLS working together — mastering this stack makes you faster at diagnosing outages that look like application bugs.
Related reading
- DNS explained — hostname resolution that precedes every TCP connection
- TLS and HTTPS explained — encryption layered on top of TCP port 443
- HTTP/2 and HTTP/3 explained — how modern HTTP multiplexes over TCP and QUIC
- Load balancing explained — distributing TCP connections across backend servers