Lab 10 - Socket Programming: Multiple Clients


Expand for the usual lab directions
  • Submit your completed lab online to CourSys (not Canvas, not GitHub).
    • Labs are marked on completion, not correctness, so complete each part to the best of your ability and learn.
    • Lab is due Sunday and may be submitted up to 3 days late. Further extensions possible only in exceptional cases.
  • It is recommended that students attend in-person lab sections for lots of support!
    • You are invited to come to any (or more than one) lab section.
    • There is no need to attend the section you are enrolled in.
    • There is no need to attend any lab sections: there is no attendance taken.
    • You can complete the lab on your own time or own computer if you like.
    • Time suggestions are given here to guide students who are working on the lab during lab times. However, the entire lab must be completed by everyone for marks.
  • While completing these labs, you are encouraged to help your classmates and receive as much help as you like. Assignments, however, are individual work and you must not work with another person on assignments.
    • I recommend coming to the lab and working with someone.
    • Failing that, I recommend getting together with someone in the class outside of lab time to work through the lab together.
    • Failing that, you are welcome to complete the lab exercise without any collaboration.
    • Each student must submit their lab to get marks.
    • Academic honesty expectations for labs are that each student types their own lab solution. It is OK to share ideas and help each others with specific coding issues and design. It is not permitted to submit another student's file for credit.
  • If using CSIL lab PC:
    • [Only CSIL PC] If in Windows, reboot to Linux; while booting, select Ubuntu from boot menu.
    • [Only CSIL PC] Don't setup GitHub tokens in the cmpt201 container because it may be shared with other users.
    • [Only CSIL PC] Delete any possible previous docker container before starting the lab:
      docker rm cmpt201
    • [Only CSIL PC] When done your lab, copy your solution out of the container, then execute the above docker command to delete your docker container to leave it clean for the next user.
  • You do not need to use record.


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


  1. Clone the Lab 10 starter project
     
  2. 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 or client.c, re-run the appropriate build_and_run_xxxxxx.sh script.
       
  3. 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..

  1. 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.
       
  2. 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.
       
  3. 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().
       
  4. 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() and close() respectively.
       
  5. 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?
         
  6. 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

3. [Optional] Challenges


  1. 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?
  2. Optional: Switch to using an atomic integer (#include <stdatomic.h>) for the count of number of messages received.
  3. 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:

  1. client.c
  2. 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.