Whilst asynchronous IO (non-blocking descriptors with select/poll/epoll/kqueue etc) is not the most documented thing on the web, there are a handful of good examples.
<
You want to decouple "io" from processing, at which point the code you read will become very readable. Basically you have:
int read_io_event(...) { /* triggers when we get a read event from epoll/poll/whatever */
/* read data from "fd" into a vstr/buffer/whatever */
if (/* read failed */) /* return failure code to event callback */ ;
if (/* "message" received */) return process_io_event();
if (/* we've read "too much" */) /* return failure code to event callback */ ;
return /* keep going code for event callback */ ;
}
int process_io_event(...) {
/* this is where you process the HTTP request/whatever */
}
...then the real code is in process event, and even if you have multiple requests responses it's pretty readable, you just do "return read_io_event()" after setting a state or whatever.