Building Network Servers
Let's see how our abstractions hold up when we go outside the boundary of a single computer.
- Modify an existing server to efficiently handle multiple connections
- Apply what we learned about synchronization to manage our server
Get the Code
We're working in the
l25 directory of the
Putting our server under load
When we left our serviceserver (form the video), we used serviceserver-02, which looped handling a single request at a time. Real servers need to handle many simultaneous requests. Our work today will walk us through some different approaches to handling multiple connections simultaneously.
serviceserver.c file in the
l25 directory is the version that handles one connection at a time. Run it and put it in the background. Then fire up the
serviceblaster program. Notice how slowly connections are handled. Kill the blaster and then kill the server you have running in the background.
A Process per Connection
One way we might handle multiple simultaneous connections would be to have the main server thread repeatedly listen on the accepting socket, but then fork off a child thread to handle each request.
serviceserver.c file into
serviceserver-process.c. Make the following changes to that file (and add
serviceserver-process to the Makefile on the
First, we want the server to automatically reap the child processes that it's going to spawn, so add the line:
at the beginning of main.
Now, rather than calling handle_connection in your main server, modify the code to fork a new child that runs only as long as it takes to handle the connection (i.e, it should exit after it processes the connection message).
When that's working, try running the
serviceblaster client against that server.
1. How does its behavior compare to the original
A Thread per Connection
OK, so a process per connection is too resource intensive. What about threads! After all, we did just learn how to use pthreads. Let's give it a try! Rather than forking off a process per connection, let's just fork off a thread and handle the request. Implement this in a field called
2. What happens?
Thread Pools (1)
One way we limit resource usage is to limit the number of concurrent threads we have active at any time. Use what you've learned about synchronization to impose a limit on the total number of threads the server might have active simultaneously. Don't change your overall structure though -- create a new thread when you can and have a thread exit after it handles a request. Name this version of the server
3. How well does that perform?
Please take a minute to fill out this survey.