Objective |
The objective of this homework is to: Understand the use of multiple threads Develop a custom multithreaded web server. Understand the use of critical sections created using a std::mutex and std::lock_guard. |
Starter code
A short starter code is supplied in homework8.cpp to streamline testing. You may reuse code from previous homework and exercises as you see fit.
However, for testing a custom multithreaded test client is supplied in bank_client.cpp along with input files. You are expected to separately compile and run the supplied program for testing your custom web-server as shown further below.
F | Despite all the testing, it still takes a human to review a program to decide if a program is correctly multithreaded. Hence, the even if your program passes all the tests in the CODE plug-in it could still be incorrectly multithreaded. Consequently, double-check your solution to ensure you are correctly multithreading your program in order to earn full points for this homework. |
Responses
The responses from your server should be in the following standard HTTP format, with each HTTP header lines only terminated with a r
. The message at the end of the headers does not have any newline characters.
HTTP/1.1 200 OK
Server: BankServer
Content-Length: 19
Connection: Close
Content-Type: text/plain
Account 0x01 created
Note: The Content-Length corresponds to the length of the message in the HTTP response. The message should not have any newline characters in it.
Requirements
In this homework, you are expected to develop a simple multithreaded banking application that operates using standard HTTP requests and responses. The bank consists of a collection of accounts. Each account is identified by a unique account ID (a std::string) and its associated balance (double). This information must be stored as a std::unordered_map, with the account ID serving as the key.
The bank web-server is expected operate as follows:
- The bank server should be developed using the supplied runServer as the top-level method. This method should loop forever and accept connections from web-clients.
- For each connection, it should use a separate detached thread for processing the request from the user. Each request will be a standard HTTP GET request in the form (with each line terminated with a r
):
GET /TransactionInfo HTTP/1.1
Host: localhost:4000
Connection: close
Where, TransactionInfo is a standard query string in the form:
trans=cmd&acct=AccountID&amount=amt. The cmd indicates type of
operation to perform. The account and amount information are optional. The expected operation for and output for each command is shown below.
Note: The commands below assume that account name is 0x01. However, the account ID can be different/vary. So do not hardcode account ID to 0x01.
TransactionInfo (all in 1 line) Description of required Expected msg from operation server in HTTP response | ||
trans=reset Clear out all accounts All accounts reset | ||
trans=create&acct=0x01 Create account only if account Account 0x01 created does not exist. or | ||
Account 0x01 already exists | ||
trans=credit&acct=0x01&am ount=20.25 | Add specified amount to account, if account exists | Account balance updated or |
Account not found | ||
trans=debit&acct=0x01&amo unt=20.25 | Subtract specified amount to account, if account exists | Account balance updated or |
Account not found | ||
trans=status&acct=0x01 | Return account balance with exactly 2 decimal places via:os << std::fixed << std::precision(2) << 20.25; | Account 0x01: $0.00 |
Account not found | ||
Note: The message Account not found is returned if the specified account ID does not exist. The response is always in the format shown earlier but the specific message in the response will vary as shown above. |
Multithreading Notes
- The web-server should use 1 detached thread per client connection
- Dont forget to read (and ignore) request headers from the client. Otherwise your server will not operate correctly with the web-browser or any standard web-clients.
- You may suitably use 1 global std::mutex variable to avoid race conditions
- Ensure checking for bank account and operating on accounts is performed within the same critical section. Otherwise you will experience a race condition.
- Do not perform I/O in the critical section. Keep critical sections as short as possible.
Functional testing
A custom multithreaded test client is supplied along with this homework for testing your server. You will need to compile the tester program once as shown below:
$ g++ -g -Wall -std=c++14 bank_client.cpp -o bank_client -lboost_system -lpthread
Base case [15 points] Will be strictly enforced
The base case tests require the server to operate correctly in single threaded mode. The base case is essentially CSE-174 level simple string processing. Hence, if you find the base case to be hard,
that means you are missing some of the key concepts and programming skills from CSE-174 and | |
CSE-278. | The base case testing should be conducted as shown below, assuming your server is |
listening on port 6000.
$ ./bank_client base_case_req.txt 6000
Note: On correct operation, the client generates the following output:
Finished block #0 testing phase.
Finished block #1 testing phase.
Testing completed.
Multithreading case [10 points]
Once the base case is operating correctly, multithreading is relatively straightforward using detached threads. However, ensure you use critical sections (using std::lock_guard will make your life easier) when performing various operations. The multithreading testing should be conducted as shown below, assuming your server is listening on port 6000.
$ ./bank_client mt_test_req.txt 6000
Note: On correct operation, the client will generate the following output:
Finished block #0 testing phase.
Finished block #1 testing phase.
Finished block #2 testing phase.
Finished block #3 testing phase.
Finished block #4 testing phase.
Testing completed.
Reviews
There are no reviews yet.