One important hurdle to overcome, when implementing any server software, is accepting and parsing requests from multiple clients simultaneously.
Consider a client that sends only the beginning of an HTTP request, followed by a delay, and then the remainder of the HTTP request. In this case, we cannot respond to that client until the entire HTTP request is received. However, at the same time, we do not wish to delay servicing other connected clients while waiting. For this reason, we need to buffer up received data for each client separately. Only once we've received an entire HTTP request from a client can we respond to that client.
It is useful to define a C struct to store information on each connected client. Our program uses the following:
/*web_server.c except*/
#define MAX_REQUEST_SIZE 2047
struct client_info {
socklen_t address_length...