Ask HN: Resources for Building a Webserver in C?
66 comments
"Write a tiny web server in C" was a standard exercise when I was in high school, and later again in university. I think I did that at least 3 times as an assignment so far.
I reused the final version for a different university exercise instead of bothering with Tomcat as I was required, and back in 2015, dumped the end result here: https://github.com/AgentD/websrv where I kept adding to it for a while for fun.
The HTTP 1.x protocol itself is pretty dead simple (if you ignore chunked requests/responses and such) and the more interesting part was actually the socket code.
Back in school, our teacher had us write a simple forking server and consult the corresponding man pages (man 2 socket, man 7 socket, man 7 tcp). It was an acceptable minimal solution to not even look at the client request, respond with a static string containing a dummy response header and HTML page, which absolutely works. Bonus points for parsing the request path and sending a file back, more extra points if the path was a directory and your server sends back an "index.html" file, further points if it instead generates an HTML directory listing on the fly.
When I visited our former teacher a couple years ago, he had modified the exercise somewhat. He brought a Beagle Bone Black with him to class, with a bunch of I2C sensors attached to it, and the extended exercises now revolve around reporting temperature/humidity/... to the browser.
So, for "resource" I recommend the HTTP example on Wikipedia, as well as "Beej's guide to network programming" (as have others), as well as the man pages for quick reference.
I reused the final version for a different university exercise instead of bothering with Tomcat as I was required, and back in 2015, dumped the end result here: https://github.com/AgentD/websrv where I kept adding to it for a while for fun.
The HTTP 1.x protocol itself is pretty dead simple (if you ignore chunked requests/responses and such) and the more interesting part was actually the socket code.
Back in school, our teacher had us write a simple forking server and consult the corresponding man pages (man 2 socket, man 7 socket, man 7 tcp). It was an acceptable minimal solution to not even look at the client request, respond with a static string containing a dummy response header and HTML page, which absolutely works. Bonus points for parsing the request path and sending a file back, more extra points if the path was a directory and your server sends back an "index.html" file, further points if it instead generates an HTML directory listing on the fly.
When I visited our former teacher a couple years ago, he had modified the exercise somewhat. He brought a Beagle Bone Black with him to class, with a bunch of I2C sensors attached to it, and the extended exercises now revolve around reporting temperature/humidity/... to the browser.
So, for "resource" I recommend the HTTP example on Wikipedia, as well as "Beej's guide to network programming" (as have others), as well as the man pages for quick reference.
Come to think of it, another surprisingly simple protocol you might want to have a shot at for the fun is VNC.
It's also really rewarding to end up with a picture on the screen, once it works. Nowadays the entry barrier to real-time graphics programming is IMO really darn high for beginners, but a simplistic VNC server might get you a step closer to the MS-DOS days, where we could literally draw pixels into RAM.
(Or, you could just extend your tiny HTTP server to support Motion JPEG, which is basically just a single HTTP response header, followed by a diarrhea of JPEG images.)
It's also really rewarding to end up with a picture on the screen, once it works. Nowadays the entry barrier to real-time graphics programming is IMO really darn high for beginners, but a simplistic VNC server might get you a step closer to the MS-DOS days, where we could literally draw pixels into RAM.
(Or, you could just extend your tiny HTTP server to support Motion JPEG, which is basically just a single HTTP response header, followed by a diarrhea of JPEG images.)
Beej is fantastic resource!
This sounds like a ton of fun. I would have enjoyed this educational path.
I agree that writing the network code is more interesting. Perhaps make a really simple proxy server that accepts connections and forwards data to another http server
Where did you go to school? And how come every college educated (mostly in the US) developer I've met has never done that before...
As students c.a 2004 we were tasked with writing a MTA.
Actually, many MTAs.
Divided in small teams (1-3 people), each MTA would ultimately be pointed to the next MTA, and the teacher would use telnet to send a message over SMTP to the first one, the goal being that the message had to reach the last one in the chain.
Grades were attributed based on whether a team's implementation failed, crashed, mangled the message and whatnot, and also as a whole to promote team spirit all in good faith and sports.
It was quite fun.
(pretty confident we did HTTP things too although I have no actual recollection of it)
Actually, many MTAs.
Divided in small teams (1-3 people), each MTA would ultimately be pointed to the next MTA, and the teacher would use telnet to send a message over SMTP to the first one, the goal being that the message had to reach the last one in the chain.
Grades were attributed based on whether a team's implementation failed, crashed, mangled the message and whatnot, and also as a whole to promote team spirit all in good faith and sports.
It was quite fun.
(pretty confident we did HTTP things too although I have no actual recollection of it)
Austria, HTL from age 14 to 19 (https://en.wikipedia.org/wiki/H%C3%B6here_Technische_Lehrans...). Wikipedia calls it college for some reason, our English teacher always called it a high school (with a focus on engineering disciplines; EE in my case) and compared it to such when showing us charts of education systems in UK, US vs Austria.
I'm not sure how various schools/countries do ICT education in comparison, but I at least heard that friends of mine who stayed in grammar school past age 14 were exposed to Borland Delphi at some point.
Every time the topic "tiny webserver in C" come up on HN, I always thought that the people who never did something like this were perhaps self-taught (similar to "write a tiny shell in C" which was also a standard exercise in our universities operating systems course). I have a hard time trying to imagine how one could possibly teach a college or university level course on networking without doing exercises like that.
I'm not sure how various schools/countries do ICT education in comparison, but I at least heard that friends of mine who stayed in grammar school past age 14 were exposed to Borland Delphi at some point.
Every time the topic "tiny webserver in C" come up on HN, I always thought that the people who never did something like this were perhaps self-taught (similar to "write a tiny shell in C" which was also a standard exercise in our universities operating systems course). I have a hard time trying to imagine how one could possibly teach a college or university level course on networking without doing exercises like that.
This is priceless
https://acme.com/software/thttpd/
Here's a 2000 line web server I wrote in C (with a focus on readability) which runs https://ipv4.games/ You can read the code at https://github.com/jart/cosmopolitan/blob/master/net/turfwar... This web server runs on a single VM. It was handling about 300 write requests per second earlier today. You can monitor its metrics here: https://ipv4.games/statusz It uses *NSYNC as its multi-threaded locking primitives, which was designed by the guy who created Google's lock server. This service is frequently targeted by hackers so you can learn a lot about things like DDOS protection by reading the source.
Beej's guide to network programming: https://beej.us/guide/bgnet/
This guide is great for introducing the bsd socket api but this is really not the API you want to use if you want to create a production quality web server in C in 2022. You need the uring io API.
Might want to check out:
https://unixism.net/loti/tutorial/webserver_liburing.html
(and maybe the older tutorial too):
https://unixism.net/2019/04/linux-applications-performance-i...
https://unixism.net/loti/tutorial/webserver_liburing.html
(and maybe the older tutorial too):
https://unixism.net/2019/04/linux-applications-performance-i...
Bookmarked. Thanks for the link.
Unix Network Programming by W. Richard Stevens and parts of The Linux Programming Interface by Michael Kerrisk
This is pretty much the bible on the topic. At least on sockets programming in general, I don't think it covers HTTP.
Ordered. Thanks!
Hands-On Network Programming with C by Lewis Van Winkle is a really good intro book for network programming with C.
Ordered. Thank you for the recommendation.
Someone on HN made this [0] a couple of weeks or months ago. You code a web server to solve each of the different problems. It's language agnostic but it looks like a great way to learn.
[0] https://protohackers.com/
[0] https://protohackers.com/
You might find my epollserver interesting.
It multiplexes multiple clients (sockets) over a thread, so you can write an event loop in each thread and serve far more requests per thread than you could if it was one thread per client or one process per client. (epollserver_threaded.c)
It uses a thread safe multiconsumer multiproducer ringbuffer to communicate between threads.
https://github.com/samsquire/epoll-server
I use Alexander Krizhanovsky's of Tempesta technologies Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
https://www.linuxjournal.com/content/lock-free-multi-produce...
It multiplexes multiple clients (sockets) over a thread, so you can write an event loop in each thread and serve far more requests per thread than you could if it was one thread per client or one process per client. (epollserver_threaded.c)
It uses a thread safe multiconsumer multiproducer ringbuffer to communicate between threads.
https://github.com/samsquire/epoll-server
I use Alexander Krizhanovsky's of Tempesta technologies Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
https://www.linuxjournal.com/content/lock-free-multi-produce...
This sounds really interesting. Thanks for the share.
Thanks for your kind thanks.
I'm currently working on a generalised approach to structuring multiple multithreaded components that run kernel threads and lightweight threads similar to golang.
My 1:M:N userspace scheduler multiplexes N lightweight threads onto M kernel threads but it's a different repository. It has one kernel thread and preempts loops by setting them to their limit.
Ideally they should be merged into one codebase.
https://GitHub.com/samsquire/preemptible-thread
I'm currently working on a generalised approach to structuring multiple multithreaded components that run kernel threads and lightweight threads similar to golang.
My 1:M:N userspace scheduler multiplexes N lightweight threads onto M kernel threads but it's a different repository. It has one kernel thread and preempts loops by setting them to their limit.
Ideally they should be merged into one codebase.
https://GitHub.com/samsquire/preemptible-thread
Unix Network Programming by Stevens and TCP/IP Illustrated by Fall and Stevens are must reads. There are many subtleties and pitfalls in writing low level network code and those books comprehensively cover everything.
Edit: I’ve heard that the first edition of TCP/IP illustrated has considerably more readable prose, so if you’re not doing IPv6 maybe get it instead. Apparently the 2nd edition with Fall is more of a rewrite with a considerable number if technical errors so I can’t recommend it having not read it.
Edit: I’ve heard that the first edition of TCP/IP illustrated has considerably more readable prose, so if you’re not doing IPv6 maybe get it instead. Apparently the 2nd edition with Fall is more of a rewrite with a considerable number if technical errors so I can’t recommend it having not read it.
Here's a fun webserver I wrote 20 years ago. It uses a pool allocator to make allocations easy to track (gives you a lot of the benefits of garbage collection, but from pure C), and it also uses an interesting "inversion of control" (similar to "green threads" or coroutines) allowing the server to be written as straight-line code but actually being implemented using poll.
It actually ran a production site at an old company I worked at until fairly recently.
http://git.annexia.org/?p=c2lib.git;a=tree http://git.annexia.org/?p=pthrlib.git;a=tree http://git.annexia.org/?p=rws.git;a=tree
It actually ran a production site at an old company I worked at until fairly recently.
http://git.annexia.org/?p=c2lib.git;a=tree http://git.annexia.org/?p=pthrlib.git;a=tree http://git.annexia.org/?p=rws.git;a=tree
I've written a fully functioning web server using a managed language, with SSL, multi-threading, Keep-Alive and chunked content encoding.
I suggest to start with understanding the HTTP protocol by reading the RFC. The most important part is how to start and end the HTTP message (by closing connection, by Content-Length, or by chunked encoding).
Then next important bit is how to receive the HTTP message. Network APIs will ask for number of bytes to receive, so you'll need to know exactly how the message ends.
Stick with the RFC, programming language doesn't matter because socket APIs are very much the same.
I suggest to start with understanding the HTTP protocol by reading the RFC. The most important part is how to start and end the HTTP message (by closing connection, by Content-Length, or by chunked encoding).
Then next important bit is how to receive the HTTP message. Network APIs will ask for number of bytes to receive, so you'll need to know exactly how the message ends.
Stick with the RFC, programming language doesn't matter because socket APIs are very much the same.
https://tools.suckless.org/quark/ is a honorable mention, very elegant code.
If you want to do something simple, read Beej's Guide to Networking (many other have recommended it in this thread) to learn networking fundamentals and C APIs. Next, learn about HTTP - MDN is a good resource, but may go too in depth for this project at times. HTTP 1.1 is super simple. The best thing about HTTP? It's all just plain text and newlines. Parsing it is super easy. This is a good learning exercise - good luck on it.
> I'd also be interested in opinionated writeups/positions.
Ok then! Writing a web server in C is bloody stupid. A web server's performance is mostly limited by concurrency issues and various IO latencies, not by how fast the machine code runs. Thus, there are zero advantages to writing a web server in C and mountains of disadvantages. Save your time and write your web server in a good language, Java, Go, Python, Nim, but not C.
Ok then! Writing a web server in C is bloody stupid. A web server's performance is mostly limited by concurrency issues and various IO latencies, not by how fast the machine code runs. Thus, there are zero advantages to writing a web server in C and mountains of disadvantages. Save your time and write your web server in a good language, Java, Go, Python, Nim, but not C.
I've built one with Python along with a custom WSGI app.
Also, Apache and NGINX say hello.
Also, Apache and NGINX say hello.
I remember using this tutorial to build a web server that handles sockets.
Short source code, excludes edge cases, but useful to understand the gist of web servers.
https://www.ibm.com/support/pages/how-does-webserver-actuall...
Short source code, excludes edge cases, but useful to understand the gist of web servers.
https://www.ibm.com/support/pages/how-does-webserver-actuall...
The tutorial has been moved to https://nmon.sourceforge.net/pmwiki.php?n=Site.Nweb.
Thanks for the share.
Thanks for the share.
If you are looking at performance
I found pulling this code apart a great learning experience.
https://github.com/fredrikwidlund/libreactor
https://github.com/fredrikwidlund/libreactor
Complete OpenBSD + Sqlite + C + httpd toolkit for building websites.
http://bsd.lv/
I recommend swapping out C for a safer&more productive language.
http://bsd.lv/
I recommend swapping out C for a safer&more productive language.
Is there a safe and productive language that produces binaries that run fast? Between the rising energy prices and CO2 pollution it would be very irresponsible to use languages like Python or Ruby.
Althttpd source is great resource
https://sqlite.org/althttpd/file/althttpd.c
https://sqlite.org/althttpd/file/althttpd.c
For embedded: https://github.com/cesanta/mongoose/
[deleted]
This one is more about writing web server applications in C. The stack already has both a webserver that talks with the app via FastCGI, and a database (SQLite).
you could try using https://libuv.org/ and https://github.com/h2o/picohttpparser
If you wish, use the source. (Almost?) all early webservers were written in C.
Being largely unfamiliar with C, I would prefer conceptual resources over source code. The why is more important than the how. Hopefully that makes sense?
conceptually things are pretty limited - this is really simple if you are just playing around, and are just doing http 1
it helps to have some decent way of representing the header to send to the handler, C doesn't really have a great story here
I think the only funky thing is dealing with all the various body modes. so you will need to make some kind of protocol to deal with handlers and incremental updates if that's a thing for your use case.
I would just do the normal thing, read the rfc and spit out a couple hundred lines that talks to your browser...and then decide where if anywhere you need to go from there
o bind a socket
o manage incoming connections
o parse http headers
o 'routing' - demultiplex handlers based on URL
o encode response
unless its a little embedded thing one usually uses some kind of select/epoll machinery to multiplex the work on each channel. I guess thread-per-request is another model that works at moderate connection counts.it helps to have some decent way of representing the header to send to the handler, C doesn't really have a great story here
I think the only funky thing is dealing with all the various body modes. so you will need to make some kind of protocol to deal with handlers and incremental updates if that's a thing for your use case.
I would just do the normal thing, read the rfc and spit out a couple hundred lines that talks to your browser...and then decide where if anywhere you need to go from there
A little context:
I'm specifically interested in compressing my analytics stack. I'm currently interacting with HTTP Messages at a higher level. The problem, as I see it, is the webserver is already doing this work but without useful output. I'd like to implement my analytics paradigm natively at the webserver level.
I'm specifically interested in compressing my analytics stack. I'm currently interacting with HTTP Messages at a higher level. The problem, as I see it, is the webserver is already doing this work but without useful output. I'd like to implement my analytics paradigm natively at the webserver level.
I'm not sure I follow - you want a smart, small webserver that takes in a http request and updates an analytic store based on headers?
Sounds like something nginx might handle via lua scripting?
Otherwise, maybe you want: https://github.com/lammertb/libhttp
Or you might want to look at either of:
https://www.acme.com/software/thttpd/
https://github.com/openbsd/src/tree/master/usr.sbin/httpd
If you really want to build (another) web server in C.
Not entirely clear why want to use C for this, though?
Sounds like something nginx might handle via lua scripting?
Otherwise, maybe you want: https://github.com/lammertb/libhttp
Or you might want to look at either of:
https://www.acme.com/software/thttpd/
https://github.com/openbsd/src/tree/master/usr.sbin/httpd
If you really want to build (another) web server in C.
Not entirely clear why want to use C for this, though?
for some applications it really might be easier to write a little thing than integrate into some giant framework. and I do think that building these things really helps one understand what's going on in all those layers
but I have to agree about C. unless the whole point is to ingrate with some existing codebase, there are several language choices which should turn this from a day or two of work to an hour or two - with a more robust outcome
but I have to agree about C. unless the whole point is to ingrate with some existing codebase, there are several language choices which should turn this from a day or two of work to an hour or two - with a more robust outcome
I want to consume HTTP headers at the lowest possible level. The webserver would output a custom log file for direct consumption.
There are certainly off the shelf options, but I enjoy reinventing the wheel and dislike dependencies. I'd like to use C because I have interest in OS level webservers.
There are certainly off the shelf options, but I enjoy reinventing the wheel and dislike dependencies. I'd like to use C because I have interest in OS level webservers.
I would probably go for rust over c if the only reason for c is "os level". But either way, this is for requests from "real" http clients, eg: web browsers? Presumably you're already "trapped" at a pretty high level, like tls, http/2 etc?
Otoh, if low level is what you want, maybe look at:
https://2ton.com.au/rwasa/
and/or the library it is built on.
On the other hand, if you just want to log headers to a file, caddy can do that in a few lines:
https://caddyserver.com/docs/caddyfile/directives/log
AFAIK it can't log request bodies out of the box (like the content of a POST).
Otoh, if low level is what you want, maybe look at:
https://2ton.com.au/rwasa/
and/or the library it is built on.
On the other hand, if you just want to log headers to a file, caddy can do that in a few lines:
https://caddyserver.com/docs/caddyfile/directives/log
AFAIK it can't log request bodies out of the box (like the content of a POST).
this is a 500 line server running in kernel mode on nanos
https://github.com/nanovms/nanos/blob/master/src/http/http.c
https://github.com/nanovms/nanos/blob/master/src/http/http.c
In that case you might be better off looking at writing a plugin for your existing webserver.
nginx, apache, etc, all allow writing modules that can be invoked at various parts of the HTTP-communication.
nginx, apache, etc, all allow writing modules that can be invoked at various parts of the HTTP-communication.
I don't technically run a webserver. I've built around Azure App Services which runs gunicorn behind the scenes.
Also, I rather own the majority of my stack even though its slower, harder, and more problematic.
Also, I rather own the majority of my stack even though its slower, harder, and more problematic.
Parse server logs, if that helps.
Unfortunately, having done the same, there are a lot of lessons learned in existing source code that you won’t find elsewhere.
One of my favorite things to read is RFC 1945
C is the native language of Unix, so in a way it really is the language for formally discussing Unix concepts.
I'm surprised this isn't the popular opinion.
Maybe redbean made by jart?
Read the mongoose source code.
What's your favorite book/post/lecture/whatever? I'd also be interested in opinionated writeups/positions.