At 1337 I wrote an HTTP server in C++ from scratch — no HTTP libraries. Just sockets, an event loop, and a parser I had to write myself. Nothing demystifies a framework like reimplementing the floor it stands on.
The event loop is not magic
"Non-blocking" stops being a buzzword the moment you write the epoll_wait loop yourself. One thread, a readiness list, and a strict rule: never call anything that can block.
int n = epoll_wait(epfd, events, MAX, -1);
for (int i = 0; i < n; ++i) {
int fd = events[i].data.fd;
if (fd == listen_fd) accept_new_connection();
else if (events[i].events & EPOLLIN) read_request(fd);
else if (events[i].events & EPOLLOUT) flush_response(fd);
}Backpressure. A socket’s send buffer fills and write() returns EAGAIN. You must stop, register for EPOLLOUT, and resume later. Every framework is quietly managing this dance for you.
What carried over
- A request is just bytes you have to frame yourself — Content-Length and chunked encoding exist for a reason
- Parsing is a state machine; “just split on newlines” dies on the first edge case
- Timeouts and partial reads are the common case, not the exception
- Every abstraction has a cost you can now actually see
I learned the stack from the socket up — and I’ve never since trusted a framework blindly to do it for me.
Now when a framework misbehaves, I don’t guess. I know which syscall it’s standing on.