Metadata
| Field | Value |
|---|---|
| Slug | http-tcp-fundamentals |
| Difficulty | Beginner |
| Estimated Reading Time | 12 min |
| Estimated Coding Time | 20 min |
| Tier | 0 — Networking Fundamentals |
| Implementation Language | Python |
| SEO Description | Learn how HTTP and TCP/IP work internally — the transport and application layer protocols behind every distributed system, with a from-scratch Python implementation. |
1. Overview
What problem does it solve?
Two computers need to exchange data reliably over an unreliable network. TCP solves the transport problem (reliable, ordered byte delivery), and HTTP solves the application problem (a structured request-response protocol for transferring hypertext, APIs, and data).
What breaks without it?
Everything. Every system design — TinyURL, WhatsApp, Uber, Netflix — starts with a client sending an HTTP request. Without understanding HTTP:
- You can't reason about latency (connection setup, TLS handshake, keep-alive)
- You can't design APIs (methods, status codes, headers)
- You can't debug production issues (timeouts, retries, connection pooling)
- You can't compare protocols (HTTP/1.1 vs HTTP/2 vs HTTP/3, REST vs WebSocket)
2. Motivation
Why was TCP invented?
In the 1970s, the early ARPANET used NCP (Network Control Program), which assumed a reliable underlying network. As the network grew, packets got lost, duplicated, and reordered. Vint Cerf and Bob Kahn designed TCP (1974) to provide reliable, ordered, error-checked delivery over an unreliable network (IP).
Why was HTTP invented?
In 1989, Tim Berners-Lee at CERN needed a way for physicists to share documents across the internet. He created HTTP as a simple text-based protocol: send a request with a method and path, get a response with a status code and body. HTTP/0.9 (1991) only supported GET. HTTP/1.0 (1996) added headers, status codes, and content types. HTTP/1.1 (1997) added persistent connections and chunked transfer.
3. Real-World Usage
| System | How HTTP/TCP is used |
|---|---|
| Every web application | Client-server communication |
| TinyURL | GET /abc123 → 301 redirect |
| Initial connection setup, message delivery fallback | |
| Netflix | Video chunk delivery over HTTP (DASH/HLS) |
| Uber | REST APIs for ride requests, driver location updates |
| Kafka | Producer/consumer APIs (custom TCP protocol over TCP sockets) |
| Redis | RESP protocol over raw TCP sockets |
| Kubernetes | API server exposes REST over HTTPS |
| Cassandra | CQL binary protocol over TCP |
4. Prerequisites
- Basic programming knowledge (variables, functions, loops)
- Understanding of what a "network" is (machines connected together)
- No previous building blocks required — this is Block 001
5. Visual Explanation
The TCP/IP Layer Model
┌─────────────────────────────────────────────┐
│ Application Layer (HTTP, DNS, SMTP) │ ← You write code here
├─────────────────────────────────────────────┤
│ Transport Layer (TCP, UDP) │ ← Reliable delivery
├─────────────────────────────────────────────┤
│ Network Layer (IP) │ ← Routing between hosts
├─────────────────────────────────────────────┤
│ Link Layer (Ethernet, Wi-Fi) │ ← Physical transmission
└─────────────────────────────────────────────┘
TCP Three-Way Handshake
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: Connection Establishment
C->>S: SYN (seq=100)
S->>C: SYN-ACK (seq=300, ack=101)
C->>S: ACK (ack=301)
Note over C,S: Connection Established
Note over C,S: Data Transfer
C->>S: HTTP Request (PSH, seq=101)
S->>C: ACK (ack=201)
S->>C: HTTP Response (PSH, seq=301)
C->>S: ACK (ack=501)
Note over C,S: Connection Teardown
C->>S: FIN
S->>C: FIN-ACK
C->>S: ACK
HTTP Request-Response Flow
Client Server
│ │
│ ──── TCP Handshake (SYN/SYN-ACK/ACK) ─────
│ │
│ GET /api/users HTTP/1.1 │
│ Host: api.example.com │
│ Accept: application/json │
│ ─────────────────────────────────────► │
│ │
│ HTTP/1.1 200 OK │
│ Content-Type: json │
│ Content-Length: 42 │
│ │
│ {"users": [...]} │
│ ◄───────────────────────────────────── │
│ │
│ ──── Connection: keep-alive ──────────
│ (reuse for next request) │
6. Internal Working
TCP — Step by Step
Problem: IP (Internet Protocol) delivers packets unreliably. Packets can arrive out of order, get duplicated, or vanish entirely.
TCP's solution — four mechanisms:
6.1 Sequencing
Every byte in the stream gets a sequence number. The receiver reassembles bytes in order, regardless of arrival order.
Sent: [seq=1, 100 bytes] [seq=101, 100 bytes] [seq=201, 50 bytes]
Arrived: [seq=201, 50 bytes] [seq=1, 100 bytes] [seq=101, 100 bytes]
Result: [bytes 1-100] [bytes 101-200] [bytes 201-250] ✓ Correct order
6.2 Acknowledgment
The receiver sends back an ACK with the next expected sequence number. If the sender doesn't receive an ACK within a timeout, it retransmits.
6.3 Flow Control
The receiver advertises a window size — how many bytes it can buffer. The sender never sends more than the window allows. This prevents a fast sender from overwhelming a slow receiver.
6.4 Congestion Control
TCP starts slow (slow start) and doubles the sending rate each round trip until it detects loss. On loss, it halves the rate (congestion avoidance). This prevents the network itself from being overwhelmed.
HTTP — Step by Step
HTTP is a text-based, stateless, request-response protocol layered on top of TCP.
6.5 HTTP Request Structure
METHOD PATH HTTP/VERSION\r\n ← Request line
Header-Name: Header-Value\r\n ← Headers (key-value pairs)
Header-Name: Header-Value\r\n
\r\n ← Empty line = end of headers
[optional body] ← Request body (POST, PUT)
6.6 HTTP Response Structure
HTTP/VERSION STATUS_CODE REASON\r\n ← Status line
Header-Name: Header-Value\r\n ← Response headers
\r\n ← Empty line
[response body] ← The actual content
6.7 Key HTTP Methods
| Method | Idempotent? | Safe? | Use case |
|---|---|---|---|
GET | ✅ | ✅ | Read a resource |
POST | ❌ | ❌ | Create a resource |
PUT | ✅ | ❌ | Replace a resource |
PATCH | ❌ | ❌ | Partial update |
DELETE | ✅ | ❌ | Remove a resource |
6.8 Key Status Codes
| Code | Meaning | System Design Relevance |
|---|---|---|
200 | OK | Successful read/write |
201 | Created | Resource created (POST) |
301 | Moved Permanently | TinyURL redirect! |
302 | Found (temp redirect) | A/B testing, feature flags |
304 | Not Modified | Cache validation (ETag) |
400 | Bad Request | Client sent invalid data |
401 | Unauthorized | Missing/invalid auth token |
403 | Forbidden | Valid auth but no permission |
404 | Not Found | Resource doesn't exist |
429 | Too Many Requests | Rate limiter triggered! |
500 | Internal Server Error | Server bug |
502 | Bad Gateway | Upstream server down |
503 | Service Unavailable | Server overloaded |
504 | Gateway Timeout | Upstream server too slow |
7. Implementation
Why Python? Python's socket module exposes raw TCP with minimal boilerplate, making the TCP→HTTP layering visible. No frameworks — just the protocol itself.
"""
001 - HTTP Server from Scratch
Demonstrates TCP socket programming + HTTP protocol parsing.
No frameworks. No libraries. Just sockets.
"""
import socket
import threading
from datetime import datetime, timezone
def parse_http_request(raw: bytes) -> dict:
"""Parse raw bytes into an HTTP request dictionary."""
text = raw.decode("utf-8", errors="replace")
lines = text.split("\r\n")
# Parse request line: GET /path HTTP/1.1
request_line = lines[0].split(" ")
method = request_line[0] if len(request_line) > 0 else "GET"
path = request_line[1] if len(request_line) > 1 else "/"
version = request_line[2] if len(request_line) > 2 else "HTTP/1.1"
# Parse headers
headers = {}
body_start = 0
for i, line in enumerate(lines[1:], start=1):
if line == "":
body_start = i + 1
break
if ":" in line:
key, value = line.split(":", 1)
headers[key.strip().lower()] = value.strip()
# Extract body
body = "\r\n".join(lines[body_start:]) if body_start < len(lines) else ""
return {
"method": method,
"path": path,
"version": version,
"headers": headers,
"body": body,
}
def build_http_response(status_code: int, body: str, content_type: str = "text/plain") -> bytes:
"""Build a raw HTTP response from components."""
reason_phrases = {
200: "OK", 201: "Created", 301: "Moved Permanently",
400: "Bad Request", 404: "Not Found", 429: "Too Many Requests",
500: "Internal Server Error",
}
reason = reason_phrases.get(status_code, "Unknown")
now = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S GMT")
body_bytes = body.encode("utf-8")
response = (
f"HTTP/1.1 {status_code} {reason}\r\n"
f"Content-Type: {content_type}\r\n"
f"Content-Length: {len(body_bytes)}\r\n"
f"Date: {now}\r\n"
f"Connection: close\r\n"
f"\r\n"
).encode("utf-8") + body_bytes
return response
# ── Simple Router ──
# In-memory "database" for demonstration
short_urls = {"abc123": "https://sourav-saha.in"}
def handle_request(request: dict) -> bytes:
"""Route requests to handlers — like a tiny TinyURL."""
method = request["method"]
path = request["path"]
# GET / → Homepage
if method == "GET" and path == "/":
return build_http_response(200, '{"status": "ok", "service": "building-block-001"}',
"application/json")
# GET /shorten?url=... → Create short URL (simplified)
if method == "GET" and path.startswith("/shorten"):
return build_http_response(201, '{"short_url": "/abc123"}',
"application/json")
# GET /<code> → Redirect (301) — this is how TinyURL works!
if method == "GET" and path.startswith("/"):
code = path[1:]
if code in short_urls:
redirect_body = f"Redirecting to {short_urls[code]}"
resp = (
f"HTTP/1.1 301 Moved Permanently\r\n"
f"Location: {short_urls[code]}\r\n"
f"Content-Length: {len(redirect_body)}\r\n"
f"Connection: close\r\n"
f"\r\n"
f"{redirect_body}"
).encode("utf-8")
return resp
# 404 for everything else
return build_http_response(404, '{"error": "not found"}', "application/json")
def handle_client(client_socket: socket.socket, address: tuple):
"""Handle a single TCP connection."""
try:
# TCP receive — read up to 4096 bytes
raw_data = client_socket.recv(4096)
if not raw_data:
return
# Parse HTTP from raw TCP bytes
request = parse_http_request(raw_data)
print(f"[{address[0]}:{address[1]}] {request['method']} {request['path']}")
# Route and respond
response = handle_request(request)
client_socket.sendall(response) # TCP send — reliable delivery guaranteed
except Exception as e:
error_resp = build_http_response(500, f'{{"error": "{str(e)}"}}', "application/json")
client_socket.sendall(error_resp)
finally:
client_socket.close() # TCP FIN — connection teardown
def start_server(host: str = "127.0.0.1", port: int = 8080):
"""
Start a TCP server that speaks HTTP.
The layering is visible:
1. socket() → Create a TCP socket
2. bind() → Attach to an address
3. listen() → Mark as a server socket
4. accept() → Wait for TCP handshake (SYN → SYN-ACK → ACK)
5. recv() → Read bytes from the TCP stream
6. parse HTTP → Interpret those bytes as an HTTP request
7. sendall() → Write HTTP response bytes to the TCP stream
8. close() → TCP teardown (FIN → FIN-ACK → ACK)
"""
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((host, port))
server_socket.listen(128) # Backlog: max pending connections
print(f"HTTP Server listening on http://{host}:{port}")
print(f"Try: curl http://{host}:{port}/")
print(f"Try: curl http://{host}:{port}/abc123 -v")
try:
while True:
# accept() blocks until a client completes the TCP 3-way handshake
client_socket, address = server_socket.accept()
# Handle each connection in a separate thread
thread = threading.Thread(target=handle_client, args=(client_socket, address))
thread.daemon = True
thread.start()
except KeyboardInterrupt:
print("\nShutting down.")
finally:
server_socket.close()
if __name__ == "__main__":
start_server()
Sample Output
$ python 001_http_server.py
HTTP Server listening on http://127.0.0.1:8080
Try: curl http://127.0.0.1:8080/
Try: curl http://127.0.0.1:8080/abc123 -v
# Terminal 2:
$ curl http://127.0.0.1:8080/
{"status": "ok", "service": "building-block-001"}
$ curl -v http://127.0.0.1:8080/abc123
< HTTP/1.1 301 Moved Permanently
< Location: https://sourav-saha.in
Redirecting to https://sourav-saha.in
$ curl http://127.0.0.1:8080/nonexistent
{"error": "not found"}
8. Complexity
| Metric | Value | Notes |
|---|---|---|
| TCP handshake | O(1) — 1.5 RTT | 3 packets: SYN, SYN-ACK, ACK |
| HTTP parsing | O(n) | n = size of request in bytes |
| Connection throughput | Bounded by bandwidth × RTT | TCP window scaling |
| Concurrent connections | ~65K per IP pair | Limited by port range (16-bit) |
| Memory per connection | ~4-10 KB | TCP buffers + socket overhead |
Scalability Characteristics
- HTTP/1.1: One request per connection at a time (head-of-line blocking). Mitigated by keep-alive and pipelining.
- HTTP/2: Multiplexed streams over a single TCP connection. Solves HOL at HTTP layer.
- HTTP/3: QUIC over UDP. Solves HOL at TCP layer.
9. Trade-offs
| Aspect | TCP | UDP |
|---|---|---|
| Reliability | ✅ Guaranteed delivery | ❌ Best-effort |
| Ordering | ✅ In-order | ❌ No ordering |
| Latency | Higher (handshake + ACKs) | Lower (no overhead) |
| Use when | Correctness matters (HTTP, DB) | Speed matters (video, DNS, gaming) |
| Head-of-line blocking | ✅ Yes (a problem) | ❌ No |
| Aspect | HTTP/1.1 | HTTP/2 | HTTP/3 (QUIC) |
|---|---|---|---|
| Transport | TCP | TCP | UDP |
| Multiplexing | ❌ | ✅ | ✅ |
| Header compression | ❌ | ✅ (HPACK) | ✅ (QPACK) |
| HOL blocking | Both layers | TCP layer only | ❌ None |
| Connection migration | ❌ | ❌ | ✅ (connection ID) |
When NOT to use HTTP
- Real-time bidirectional: Use WebSockets (Block 003)
- Ultra-low-latency RPC: Use gRPC (HTTP/2 + Protobuf)
- Streaming video: Use HTTP but with DASH/HLS chunking
- Inter-service communication: Consider gRPC or message queues (Block 023)
10. Production Evolution
| Concern | Toy Implementation | Production (Nginx/Envoy) |
|---|---|---|
| Concurrency | Thread-per-connection | Event loop (epoll/kqueue) + thread pool |
| Keep-alive | Connection: close | Persistent connections with timeouts |
| TLS | None | TLS 1.3 with session resumption (0-RTT) |
| HTTP/2 | Not supported | Full multiplexing, server push |
| Backpressure | None | Read/write buffer management |
| Timeouts | None | Read, write, idle, upstream timeouts |
| Connection pooling | New connection per request | Pool and reuse upstream connections |
| Observability | print() | Structured logs, latency histograms, trace IDs |
| Load shedding | Accept all | Max connections, queue depth limits |
11. Common Bugs
| Bug | What happens | Fix |
|---|---|---|
| Not reading full request | recv(4096) may not get everything | Loop until \r\n\r\n found, then read Content-Length more bytes |
Ignoring Content-Length | Request body is truncated or bleeds into next request | Always parse and respect Content-Length |
No timeout on recv() | Slow clients hold connections forever (Slowloris attack) | Set socket.settimeout() |
| Thread explosion | 10K concurrent connections = 10K threads = OOM | Use async I/O or thread pools |
Not handling SIGPIPE | Writing to a closed socket crashes the process | Catch BrokenPipeError |
Forgetting \r\n line endings | HTTP uses CRLF, not just LF | Always use \r\n |
12. Interview Questions
-
What happens when you type a URL in the browser and press Enter? Hint: DNS → TCP handshake → TLS → HTTP request → server processing → response → rendering
-
Why does HTTP use TCP instead of UDP? Hint: Web pages need every byte delivered correctly and in order
-
Explain the difference between HTTP/1.1 keep-alive and HTTP/2 multiplexing. Hint: Keep-alive reuses the connection but still serializes requests; HTTP/2 interleaves frames
-
What is head-of-line blocking and how does HTTP/3 solve it? Hint: TCP treats all streams as one byte stream — one lost packet blocks everything
-
How would you handle 10,000 concurrent connections on a single server? Hint: Event-driven I/O (epoll) instead of thread-per-connection — this is the C10K problem
13. Used By (Downstream Blocks)
- 002 REST API Design — layered on HTTP
- 003 WebSockets — HTTP Upgrade handshake
- 004 DNS — DNS queries travel over UDP, but zone transfers use TCP
- 007 Load Balancer — distributes TCP/HTTP connections
- 008 API Gateway — terminates HTTP, routes to upstream
- 009 Rate Limiter — operates on HTTP requests
- 010 Caching — HTTP caching headers (ETag, Cache-Control)
- 012 CDN — serves HTTP responses from edge servers
- 027 Heartbeat — health checks over HTTP
- 029 Retry & Backoff — retrying failed HTTP requests
- 035 Observability — HTTP request metrics and tracing
14. Used In (Case Studies)
| System | How |
|---|---|
| TinyURL | GET /<code> returns 301 redirect |
| Initial auth + message fallback over HTTP | |
| Uber | REST APIs for rides, drivers, payments |
| Netflix | HTTP-based video streaming (DASH/HLS) |
| YouTube | Video chunk delivery + REST APIs |
| Twitter/X | REST + streaming APIs |
| Image/video upload and feed APIs | |
| Google Drive | File upload/download over HTTP |
| Dropbox | Delta sync protocol over HTTPS |
| Kafka | REST proxy for producers/consumers |
| Redis | HTTP not used (raw TCP with RESP protocol) |
| Cassandra | HTTP not used (CQL over TCP) — but REST gateways exist |
| Kubernetes | API server is pure HTTPS/REST |
15. Related Blocks
| Relationship | Block |
|---|---|
| Previous | None — this is Block 001 |
| Parallel | 005 Hashing (independent Tier 1 block) |
| Next | 002 REST API Design |
| Next | 003 WebSockets & Long Polling |
| Next | 004 DNS & Service Discovery |
| Alternative | gRPC (HTTP/2 + Protobuf), GraphQL, MQTT (IoT) |
16. Try It Yourself
Exercise 1: Add POST Support
Extend the server to handle POST /shorten with a JSON body {"url": "https://example.com"}. Generate a random short code, store it in the short_urls dictionary, and return 201 Created with the short URL.
Exercise 2: Connection Keep-Alive
Modify the server to support Connection: keep-alive. Instead of closing the socket after one request, loop and handle multiple requests on the same connection. Add a 5-second idle timeout.
Website Metadata
| Field | Value |
|---|---|
| Hero Title | HTTP & TCP/IP Fundamentals |
| Hero Subtitle | The transport layer behind every distributed system — understand it, implement it, never be confused by it again |
| Breadcrumb | System Design → Building Blocks → HTTP & TCP/IP |
| Sidebar Category | Tier 0 — Networking Fundamentals |
| Search Keywords | http, tcp, networking, sockets, request response, status codes, tcp handshake, http methods, system design fundamentals |
| Internal Links | → 002 REST API Design · → 003 WebSockets · → 004 DNS |
| Suggested Illustration | Split-screen: left side shows a TCP handshake as a physical handshake between two servers; right side shows an HTTP request as a letter being passed through the handshake |
| Suggested Animation | Animated packet flow: SYN → SYN-ACK → ACK → HTTP Request bytes flowing → HTTP Response bytes flowing back → FIN |