Ask HN: Resources for Building a Webserver in C?
I'm starting to work with C and would like to build a webserver. I've found a few interesting writeups but would love to hear from the community.
What's your favorite book/post/lecture/whatever? I'd also be interested in opinionated writeups/positions.
66 comments
[ 0.23 ms ] story [ 157 ms ] threadit 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
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.
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?
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
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.
https://github.com/nanovms/nanos/blob/master/src/http/http.c
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).
nginx, apache, etc, all allow writing modules that can be invoked at various parts of the HTTP-communication.
Also, I rather own the majority of my stack even though its slower, harder, and more problematic.
https://unixism.net/loti/tutorial/webserver_liburing.html
(and maybe the older tutorial too):
https://unixism.net/2019/04/linux-applications-performance-i...
thanks for letting me know about civetweb, looks like it is based on a very old version?
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.
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.
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.)
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.
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)
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...
Thanks for the share.
http://bsd.lv/
I recommend swapping out C for a safer&more productive language.
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...
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
https://sqlite.org/althttpd/file/althttpd.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.
Also, Apache and NGINX say hello.
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
[0] https://protohackers.com/
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://github.com/fredrikwidlund/libreactor