Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
A web server is a TCP socket that speaks HTTP. You bind to a port, accept incoming connections, parse an HTTP request out of each one, run your handler, and write an HTTP response. Every framework you've ever used — Express, FastAPI, Actix, Gin — is a wrapper around this one loop. Understanding that loop literally (not metaphorically) is what separates people who can debug a slow server from people who can only add more of them.
Every HTTP framework you've used — Express, FastAPI, Gin, Actix — is a thin wrapper around one loop: bind a port, accept a connection, read bytes, parse HTTP, call your handler, write a response. Seeing that loop directly, without a framework in the way, makes every future abstraction legible. Four languages means four different ways to reach the same socket primitives.
curl -v http://localhost:8080/. Read every line of the response carefully — status, headers, body.:8080 and kill it; understand what bind means.:0 instead of :8080. The OS assigns a random free port. What does the server now print?Use these three in order. Each builds on the one before.
Explain, in plain language, what a web server does between 'listening on a port' and 'sending a response'. Use the words socket, accept, request, response.
Walk me through the lifecycle of one HTTP request on a single-threaded server: the accept syscall, the read, the parse, the handler, the write. Where is the CPU busy, and where is it blocked on I/O?
A single process on a modern laptop can handle tens of thousands of concurrent connections with the right architecture (epoll/kqueue, async I/O). Why, then, does a naive server with one thread per connection fall over at a few hundred? Walk me through the C10K problem and the ideas that solved it.
package main
import (
"fmt"
"net/http"
)
func main() {
// net/http does the TCP + HTTP parsing for you.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello")
})
fmt.Println("listening on :8080")
http.ListenAndServe(":8080", nil)
}go run main.go