Lab 10 - Socket Programming: Multiple Clients
Goals for this lab
- Apply your understanding of multi-threading and synchronization to client-server sockets.
- Understand a parallel flow of information to a server.
- Able to stop a thread.
Prerequisite Skills for This Lab
- Linux socket programming.
- C Skills
- Able to use structs, arrays, pointers
- Able to compile, run, and debug C programs using CMake.
Task 1: Download & Compile
- Clone the Lab 10 starter project
- Compile and run the program. Use multiple terminals:
- One for
nvim
: I suggest opening all .c files at once (nvim *.c
). You can switch between them using the commands:b1
and:b2
. - One for running the server: use
build_and_run_server.sh
. - One for running multiple clients: use
build_and_run_clients.sh
. - You only need to run
cmake
once to generate the makefiles in/build
, assuming you don't create additional .c files. - Each time you edit
server.c
orclient.c
, re-run the appropriatebuild_and_run_xxxxxx.sh
script.
- One for
- Copy-and-paste the following questions into the top of the provided
server.c
, and then answer them. You can run the code and read the code to discover the answers./* Questions to answer at top of server.c: (You should not need to change client.c) Understanding the Client: 1. How is the client sending data to the server? What protocol? 2. What data is the client sending to the server? Understanding the Server: 1. Explain the argument that the `run_acceptor` thread is passed as an argument. 2. How are received messages stored? 3. What does `main()` do with the received messages? 4. How are threads used in this sample code? */
Task 2: Server Implementation
Complete the implementation for the server (server.c
) so that..
- In server.c's
main()
function, find the// TODO
for waiting until enough messages are received.- Add code to wait until the number of messages received is at least
MAX_CLIENTS * NUM_MSG_PER_CLIENT
. - OK to use a busy wait here if you like (loop that continuously re-checks it).
- Be careful about critical sections. You'll need to use a mutex to safely read the number of messages.
- Add code to wait until the number of messages received is at least
- In server.c's
run_acceptor()
, find the// TODO
for creating the threads.- Add new code to launch a new thread for each connected client.
- Hint: All necessary parameters to
pthread_create()
are created and ready to pass in. - Remember to count the number of clients connected (
num_clients
). - When you accept a new connection, print "Client connected!\n" to the screen.
- In server.c's
run_client()
, find the// TODO
.- Call
add_to_list()
, passing in the correct arguments to add the newly created node to the list. - Hint: All parameters are readily available to just be passed in.
- Ensure you are writing thread-safe code. You'll need to lock something before calling
add_to_list()
.
- Call
- Have your program cleanly shut-down threads:
- Find the TODOs in
run_acceptor()
. - To set the stop flag, you are looking for the
run
field in the clients. - You'll need to cleanup the thread and the socket.
- Hint: use
pthread_join()
andclose()
respectively.
- Find the TODOs in
- Answer this question in the top of your server.c:
- Explain the use of non-blocking sockets in this lab.
- How are sockets made non-blocking?
- What sockets are made non-blocking?
- Why are these sockets made non-blocking? What purpose does it serve?
- Explain the use of non-blocking sockets in this lab.
- Output Sample
- Server side with 3 clients connecting:
Client connected! Client connected! Client connected! Client connected! Not accepting any more clients! Collected: Hello Collected: Apple Collected: Car Collected: Green Collected: Dog Collected: Hello Collected: Hello Collected: Hello Collected: Apple Collected: Apple Collected: Apple Collected: Car Collected: Car Collected: Car Collected: Green Collected: Green Collected: Green Collected: Dog Collected: Dog Collected: Dog Collected: 20 All messages were collected!
- Running 3 clients at once.
labs/lab10❯ ./build_and_run_clients.sh [ 33%] Built target server [ 66%] Built target client [100%] Built target server_sol Sent: Hello Sent: Hello Sent: Hello Sent: Hello Sent: Apple Sent: Apple Sent: Apple Sent: Apple Sent: Car Sent: Car Sent: Car Sent: Car Sent: Green Sent: Green Sent: Green Sent: Green Sent: Dog Sent: Dog Sent: Dog Sent: Dog
- Server side with 3 clients connecting:
3. [Optional] Challenges
- Optional: Lots of clients
- Launch many many clients to try and connect to the server. How good is performance as you scale the number of clients? How can you measure this automatically?
- Optional: Switch to using an atomic integer (
#include <stdatomic.h>
) for the count of number of messages received. - Optional: Switch to using a condition variable to track number of messages received.
Submission
Create a new file name lab10.c
which contains the code from:
client.c
- followed by the code from
server.c
.
Submit just your lab10.c
C code to CourSys by Sunday midnight. The file name must be an exact match to what CourSys is expecting, otherwise it won't accept it. Remember you can submit up to 3 days late with no penalty if needed (but please plan to get it done on time to stay up to date on the course!)
Submissions will be marked for completion. You do not need to complete any optional steps.