CS87 Lab 2:

A Client-Server Chat/Talk Program

Part 1 Due: Wednesday Feb 14 before 11:59pm
(push to your Lab02 git repo with Part1 tag by then)

Part 2 Due: Wednesday 21 before 11:59pm
(push to your Lab02 git repo with Part2 tag by then)

Part 3 Due: Wednesday 21 before 11:59pm
(required for taken-NW groups, optional for other groups)

(push to your Lab02 git repo with Part3 tag by then)

This lab should be done with your lab 2 partner

Lab 2 Goals:

Make use of the CS87 piazza page for questions and answers about socket programming, C strings, pthreads, Unix utilities. If you have taken Networks, please help your classmates who have not with socket programming questions.


Lab 2 Overview
The main focus of this lab is learning client-server socket programming and implementing a specific message protocol for clients and servers to talk to each other. You will implement two versions of a chat or talk client and server program to allow users on different machines to talk. You will be given a protocol for how clients and servers communicate, and your solution must implement the protocol such that your clients and servers can communicate with other group's.

In this lab you will implement at least 2 different versions of the client and server.

  1. The Part 1 version: allows for one-at-a-time chat session between a single client on one machine and a single server on another machine. When the current chat session ends, another client can connect to the server end and start a new chat session. The client and server alternate sending messages back and forth (in a question and answer type style).

    The Part 1 solution is due in one week. I encourage you to finish this part early and get started in on Part2.

  2. The Part 2 version: allows for a chat session between multiple clients. In this version the server does not participate in the chat itself, but fosters allowing multiple clients to connect to the chat session. Clients participating in the group chat send their message to the server and the server shares it with all of the other clients participating in the chat session. In this version, clients can "speak" at anytime; there is no specified ordering or taking turns writing messages to the group. Individual clients can also come and go in a chat session.

    The Part 2 solution is due in two weeks.

  3. The Part 3 version (optional for non-NW groups, required for NW-groups): impelement the Mean Girls Chat Server. With all the NW-groups, you will first develop a voting protocol that will allow all particpants currrently participating in a talk session decide if a new client can join in on the coverstaion. Defining a protocol means that agreeing on the message sequence for a "voting to let join" protocol--every lab group in the class must implement the same messaging protocol. Your individual implementations can use their own voting algorithm (majority, at least one "yes", random, ...) to determine if a requester gets to join in on the coverstaion.

    The Part 3 solution is due in two weeks.

This assignment is very loosely based on Unix talk, which was a very early Chat or IM system. (Note you will NOT be implementing the Unix talk protocol; instead you will implement a different protocol that has some similar general functionality.

To run talk on our system:

# to initiate a talk session with someone on another machine:
talk username  machinename
# the other person will respond with:
talk you yourmachine

# let's say Jeff from cumin does this
talk newhall lime
# Tia from lime would respond with this to start the chat session
talk knerr cumin  
AGAIN: you are NOT implementing the talk protocol, nor its exact functionality in this assignment.

Lab 2 Starting Point Repo
  1. Both you and your partner should:
    1. Create a cs87/labs subdirectory on the CS system:
      mkdir cs87
      mkdir cs87/labs
      cd cs87/labs
    2. Get your Lab02 ssh-URL from the GitHub org for our class: CS87-S18
    3. On the CS system, cd into your cs87/labs subdirectory
    4. Clone a local copy of your shared repo in your private cs87/labs subdirectory:
      git clone [your_Lab02_URL]
      Then cd into your Lab02-you-partner subdirectory.
    If all was successful, you should see the following files when you run ls:
    Makefile client.c cs87talk.c cs87talk.h server.c 
    If this didn't work, or for more detailed instructions on git see: the Using Git help page.

Starting Point files

Message Protocols
Messaging Protocols define how two parties communicate--the protocol defines both the set of application-level (higher level) messages, the send-recv exchange in handling types, and the expected format of messages.

For this lab you will implement three different high-level message protocols as part of the cs87talk protocol. The three are:

  1. HELLO: a client introduces itself to the server before talking. The server will tell the client if it can join the chat or not as part of this exchange.
  2. MSG: an endpoint will send a message to another endpoint. A client can send a MSG to a server and a server can send a MSG to the client.
  3. QUIT: a client tells a server it is done and leaving the talk session.

Each part of the protocol is begun by one party sending to the other party 1 byte message tag. The tag value is used to indicate which of the three messaging protocols the client and server should run (the expected send-recv sequence between the client and server for the interaction type is indicated by the tag).

Protocols Definitions:

And see the cs87talk.h file for type and constant definitions that you should use in your implementation of these.
  1. HELLO: this protocol is initiated by the client when it wants to start a talk session with a server (the client should initiate this immediately after the TCP connection has been established and before trying to send talk messages to the server). The send-recv behavior is defined by:
    client                                server
    ======                                ====== 
    1. send HELLO_MSG tag -------------> recv 1 byte tag
    2. send len -----------------------> recv 1 byte len
    3. send name ----------------------> recv a len bytes name string 
    4. recv 1 byte tag <---------------- send 1 byte reply tag 
                                            (HELLO_OK or HELLO_ERROR)
    The client sends 3 values to the server in this order: the HELLO_MSG tag as a 1 byte value; a 1 byte len value, which is the number of bytes in the name string; and a len bytes message containing the name string (passed as a command line argument to the client program). The client then receives the 1 byte tag response from the server, indicating if the server is letting it join the talk session.

    The server will terminate the connection after it replies HELLO_ERROR. If it replies HELLO_OK, it will update state about this connection, and create a message buffer for this client with the client's name string as a prefix. All messages set by this client will be prefixed by the string "name:" to mark that this message was "said" by this client.

  2. MSG: send a message string from a client to a server or from a server to a client:
    initiator                           other end
    =========                           =========
    1. send MSG_DATA ------------------> recv 1 byte tag value
    2. send len -----------------------> recv 1 byte len value
    3. send data ----------------------> recv len byte message
    If the server is the "other end" it always stored the received message in a string with the a "name:" prefix (obtained from the HELLO protocol) to identify the sender.

    If the client is the "other end" it just receives the message of len bytes and creates a string from the len byte message (null terminate '\0' before printing out); the client side doesn't add a prefix to received messages.

  3. QUIT: when the client wants to drop out of the chat session it sends the QUIT message tag to the server:
    client                                server
    ======                                ====== 
    1. send QUIT -----------------------> recv 1 byte tag value

    After sending QUIT, the client should close its end of the socket and exit.

    The server then cleans up any state associated with this connect, including closing its end of the socket.

    After receiving a QUIT, the server process should not exit. For Part 1, it is ready to accept a new connection. For Part 2, this client has just left the group chat.

Part 1: One Client at a time talks with a server, alternating Client-Server Talk
In the first version of this assignment you will implement a client and server program that implement the messaging protocols described above. In this version, a client will connect to a server, and then the client and server will talk back and forth, each taking turns sending a message to the other. The server will have a dedicated talk session with this client until the client terminates the connection (either it closes its end of the socket or it sends a QUIT message). The client should exit after this, but the server should not exit, instead it is now available for another client to connect to it to have a talk session.

The behavior should be:

  1. client connects to a server using the TCP protocol. Run the client with the server's IP and and the client's chat name as command line args:
    ./cs87_client tia
  2. the client initiates the HELLO protocol with the server
    1. if the server replies HELLO_ERROR, the client exits (no talking will take place)
    2. if the server responds with HELLO_OK, then the client and server will start a talk session
  3. the client and server will have a talk session that consists of some number of alternating message exchanges. the first MSG should be sent from client to server, then next from server to client, then by client to server, and so on.
  4. the talk session is ended by either the client sending a QUIT message or the server detecting that the client's end of the socket has been closed.
An individual message in (3) should be a line of texted entered by the user running the client (or server) side. I suggest using readline to read in a line of user input and return it as a string (and remember you are responsible for freeing the return string when done with it...run valgrind).

Sample Output

Here is sample output from two back-to-back talk sessions with a talk server. Your client and server program can print out any prompts and messages to the user than mine, but they should have this same alternating behavior and the server should handle only a single client connection and talk session at a time. Only after the current talk session ends, can the server accept the next talk session from another client (note where that is in the server output).

Help and Useful Utilities

Sockets and IP info:

C Programming, strings, readline library:

Part 2: Multi-client Chat
The Part 2 talk server changes the role of the server, allows multiple clients to simultaneously connect to the same server to all participate in a group chat, allows clients to send messages to others at any time (there is no predefined order or alternating behavior). In addition, new clients can enter an existing chat at any time, and current clients can leave at any time, and the chat continues on.


Sample Output

Here is sample output from a multi-client chat session. Note that the server is not a participant in the chatting, but instead forwards a message from one client to all others (and note the name prefix). Also note that clients enter and leave and the chat continues.

A note about client-side I/O

Because you will have mulitple client threads sharing the same stdin and stdout, you will see messages from other clients being printed out in the same terminal window as the prompt and the input message the human user is typing in. This is fine.

You are not required to do this, but if you want to try to implement a solution with nicer looking output, you can try using the ncurses library to split the terminal window and direct stdin to one half and stdout and stderror to the other half (this is not trivial to do). You could also try something easier and print out stdout output in a different color if it is coming from the prompt printing thread vs. from the thread that receives and prints out messages from other clients forwarded from the server. Here is some information about ncurses: Cool C libraries.

Part 3: Mean Girls Chat Server

This part is required for the lab2 partners who have taken a Networking course, and optional for the groups who have not.

For this part, you are going to add a new protocol to your Part2 solution. When a new client wants to connect to a chat session (via the HELLO protocol), the current set of clients will decide if they are going to let the new client join the chat session or not. If the current clients in the chat choose NO, then the server will reply with HELLO_ERROR and not let the new client join. If the current clients choose yes, then the server will reply with HELLO_OK and the new client can join in the group chat.

Protocol for voting in a new chat member

Your groups together will need to come up with a protocol for the server and the clients currently in the chat to make a decision. For this part, develp the messaging protocol between the server and clients in the chat to communicate a voting exchange. Your groups should agree on just the message protocol: what are the new tags, and what is the expected send-recv behavior for this protocol. This should be like defining the HELLO or MSG or QUIT protocols.

This protocol should be VERY simple. This is just the agreed message exchange between the server and clients already participating in a chat. It should be similar to one of the existing protocls like HELLO or MSG. If it starts to get longer than about 2x any of the current ones, step back and simplify.

Group's particular voting algorithms can differ, but the messaging protocol used by client and server processes should be the same; your group may choose any algorithm for tallying a result, but your group's client should know how to interpret a voting message request from another group's server, and your server should be able to have a voting interaction that includes another group's client program.

Publish your agreed upon protocol on piazza or the wiki (you can create a new page for the Lab2 Voting Protocol off the top-level class wiki page. Use the chain looking link to do this).

Some Advice: in designing the protocol try very hard to separate out the protocol design from how it will be implemented. For example, worrying about race conditions or deadlock or clients exiting are all implementation issues and should not be part of the protocol (other than ensuring that your msgs send-recvs in the protocol are not a deadlock). Focus solely on the message exchange between clients and servers to initiate a voting session and to collect votes. Similarly, the particular voting algorithm is not part of the protocol. You do not need to agree on a voting algorithm; one group could choose a majority algorithm of the client's votes, another could choose a random vote, anther could do something else with the clients' votes.

Some requirements (and not)

  1. Your group's Part 3 client/server should be able to participate in a vote with other group's Part 3 server/client. Hence the voting protocol.
  2. You should think about, and handle, clients that exit during a voting event.

You do not need to support any number of simultaneous voting of letting in new clients. For example, if a second new client tries to join the chat during the voting decision for a current new client, it is fine to serialize the voting process: first complete the voting decision about the first new client, then start the voting process on the second new client.

Before the Due Date, one of you or your partner should push your solution to github from one of your local repos to the GitHub remote repo. (it doesn't hurt if you both push, but the last pushed version before the due date is the one I will grade, so be careful that you are pushing the version you want to submit for grading):

From one of your local repos (in your ~you/cs87/labs/Lab02-partner1-partner2 subdirectory)

git add *.c *.h  
git commit
git push
Also TAG your commit: because you are going to implement your Part 2 (and Part 3) in the same repo as your Part 1, you should add a git tag to your submitted solution to a particular part.

To do this:

# list all current tags associated with a repo
git tag -l

# create a new tag named Part1 with a tag message (optional)
# and share a tag: push the tag to the origin to share it:
git tag -a Part1 -m "soln to Part1"
git push origin Part1

# checking out a specific tagged version of the code
# (checkout Part1 version of code into a local repo named my_part1)"
git checkout -b my_part1 Part1

# to list other data along with the commit for a specific tag
# (this will show the commit number, date and who created the tag):
git show Part1
You must name it exactly Part1 (and Part2 for part2, and Part3 for part3) otherwise your professor will be very sad.

If you have git problems, take a look at the "Troubleshooting" and "Advanced Features" sections of the Using git page.