HTTP servers
Bare-bones HTTP over TCP
What a web server really is
A process that
-
Creates a listening TCP socket (IP + port)
- binds an address like 0.0.0.0:80 (HTTP) or :443 (HTTPS)
-
Accepts client connections in a loop
- each accept() call blocks until a client (browser, curl) connects
- Returns a new socket just for that client conversation
-
Receives bytes (an HTTP request)
- reads from a client socket until a blank line is found
GET /index.html HTTP/1.1 Host: example.com -
Sends bytes (an HTTP response)
- writes back a raw HTTP response string
HTTP/1.1 200 OK Content-length: 8 Hello, World -
Closes the connection
- In HTTP/1.0, close immediately after sending response
- In HTTP/1.1, might keep it alive for reuse
so, in general HTTP is just a text sent over TCP frameworks mainly automate steps 3-5 and add features, but the underlying loop never changes
minimal working example
import socket
# creates a listening TCP socket
SERVER_HOST = '0.0.0.0'
SERVER_PORT = 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # reuse port after restart
# attach socker to address
server_socket.bind((SERVER_HOST, SERVER_PORT))
server_socket.listen(5)
print(f"Listening on {SERVER_HOST}:{SERVER_PORT}")
# accept client connections with a loop
while True:
# block unitl client connects
client_socket, client_addr = server_socket.accept()
print(f"Connected by {client_addr}")
# receives bytes(request)
request_data = client_socket.recv(4096).decode()
print(f"Request:\n{request_data}")
# sends bytes(response)
response = (
"HTTP/1.1 200 OK\r\n" # status line
"Content-Length: 8\r\n" # header : length of the text
"Content-Type: text/plain\r\n" # header : plain text
"\r\n"
"wazzzzap" # response body
)
client_socket.sendall(response.encode())
# close the connection
client_socket.close()
run curl http://localhost:8080 then we will get wazzzzap
So we just sent wazzzzap over a raw TCP socket, nothing complicated or anything
important notes
why blank lines matter
HTTP messages are separated into sections.
A blank line (\r\n\r\n) marks the end of the HTTP headers.
GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.0
Everything before the blank line is metadata(headers). Anything after it is considered the request body.
Without this separator, the server would not know where headers stop.
why content length matter
Content-Length tells the client how many bytes exist in the response body.
eg: Content-Length: 8 without it, the browser/client may keep waiting for more data because TCP itself does not define where the message ends.
The client needs some way to know:
- when the response body starts
- how large it is
- when it is complete
why HTTP/1.1 keeps connections alive
Opening a new TCP connection for every request is expensive.
TCP connections require:
- handshakes
- kernel resources
- extra latency
HTTP/1.1 introduced persistent connections (keep-alive) so multiple HTTP requests can reuse the same TCP connection.
This reduces:
- latency
- connection overhead
- repeated TCP handshakes
Modern browsers heavily rely on persistent connections for performance.
why TCP is used instead of UDP
HTTP needs reliable communication.
TCP provides:
- ordered packets
- retransmission of lost packets
- error checking
- reliable delivery
UDP is faster but unreliable:
- packets can arrive out of order
- packets may disappear entirely
- no guarantee data arrives
For web pages and APIs, reliability matters more than raw speed.
The browser must receive the exact bytes the server sent.
Browser
↓
TCP connection
↓
HTTP request bytes
↓
Python socket server
↓
HTTP response bytes
↓
Browser renders response
what this simple server is missing
concurrent conections
one slow client block all others, this server is synchronous/blocking. while recv() waits for data from one client, the server can’t handle another client
HTTP method routing
/home vs /about all return the same response
headers parsing
no Host, User-Agent, cookies, Auth
persistent connections
File serving
error handling
What frameworks abstract away
- socket creation
- request parsing
- routing
- middleware
- thread/event management
- response formatting
- connection pooling
- TLS/HTTPS
- logging
- error handling