This project is a basic HTTP server that supports multithreading and uses a connection queue that's thread-safe with mutex locks. It's designed to handle only "GET" requests. It is currently set to use 5 threads, meaning it can handle 5 concurrent clients, but this macro can be increased easily.
This gives it the ability to concurrently communicate with multiple clients, something any real web server would need to do, without the high overhead of forking several client processes.
In fact, to avoid the costs of repeatedly creating and destroying threads as clients connect to and disconnect from the server, it uses a thread pool design pattern. The main thread of the server process handles accepting new client connections with accept() and then passes responsibility for communicating with the new client to a “worker” thread in the thread pool.
The key to this design is the implementation of a queue data structure to pass work from the main thread to the thread pool and to coordinate the activities of each thread in the pool. The queue stores file descriptors for the client-specific connection sockets that are generated by calls to accept().
This queue is also thread safe, meaning that even with multiple threads concurrently accessing memory storing the queue, the queue’s state and data do not become corrupted. Furthermore, the queue has some helpful timing synchronization built in. When a thread tries to add to a full queue, it is blocked until space is made available. When a thread tries to remove from an empty queue, it is blocked until a data element is made available.
This involved setting up a TCP server socket and accepting incoming client connection requests in the main() function defined in the http_server.c file and then implementing HTTP request parsing and response generation by completing the HTTP library functions defined in http.c.
- TCP server socket setup and initialization with socket(), bind(), and listen()
- Server-side TCP communication with accept() followed by read() and write()
- HTTP request parsing and response generation
- Clean server termination through signal handling
- Thread creation and management with pthread_create() and pthread_join()
- Implementation of a thread-safe queue data structure with the pthread_mutex_t and pthread_cond_t primitives
Try it out for yourself!
-
Clone the Repository: First, clone this git repository into your directory of choice:
git clone git@github.com:JacksonKary/Multithreaded-HTTP-Server.git
-
Change Directory: Next, change your working directory to the newly created
Multithreaded-HTTP-Serverfolder:cd Multithreaded-HTTP-Server -
Build the Program: To build the program so it's ready to run, use the following command:
make
Note: If your environment can't execute the
makecommand, you may need to install it first. On most Unix-based systems, you can install it using:- Debian/Ubuntu:
sudo apt-get install build-essential - Fedora:
sudo dnf groupinstall "Development Tools" - macOS:
xcode-select --install
- Debian/Ubuntu:
There are many ways to test this server. By far, the simplest method is to run the makefile test command:
make testor
make test port=<port>where <port> is the port you want the server to bind to (default is 8000, valid range is 1024 through 65535).
However, the most satisfying way to test this server is to actually run it using the following command format:
./http_server <serve_dir> <port>where <serve_dir> is the directory containing content for clients to request (to use the provided directory, use server_files/).
This launches the server so it is ready to take clients. Now, connect to the server with a client. There are multiple ways to do this, but the coolest way is to send a request via an internet browser.
Typing:
localhost:<port>/<resource>
in your browser and pressing enter should connect, retrieve, and display the results on your screen. <port> is the port number the server is bound to and <resource> is the name of the item you're requesting from <serve_dir> (e.g., server_files/).
-
http_server.c: Main HTTP Server Program. -
http.h: Header file for HTTP library functions. -
http.c: Implementation of HTTP library functions. -
connection_queue.h: Header file for thread-safe queue data structure. -
connection_queue.c: Implementation of thread-safe queue data structure. -
server_files/: Folder, which contains sample files for the server to offer to clients. -
test_cases/: Folder, which contains test cases and related materials. -
testius: Script for executing test cases. -
Makefile: Build file to compile and run test cases.
A Makefile is provided as part of this project. This file supports the following commands:
-
make: Compile all code, produce an executable program. -
make clean: Remove all compiled items. Useful if you want to recompile everything from scratch. -
make clean-tests: Remove all files produced during execution of the tests. -
make test: Run all test cases. -
make test testnum=5: Run test case #5 only. -
make test port=4061: Run all test cases with server port=4061 (valid range is 1024 through 65535).