A3 - Chat Server#

250 points

Run the server (your implementation)

python3 -m a3_chat_server

Description#

When you implemented your Chat Client, you used the framework-provided server to test your implementation. When working with TCP communication, clients may only communicate with each other via a server actor, that keeps track of connected clients and distributes messages accordingly. It is now your turn to implement the Chat Server powering the Chat Client communication!

One of the main technical challenges of servers is handling multiple connections concurrently. Unlike the client, the server is likely to have multiple open connections at the same time; one for each client that is connected to it. Because it is impossible to predict when a client will send a request or message, your server needs to keep checking all connections for incoming data. Both polling and multi-threading are allowed as solutions to this problem.

Fun fact: Developing the client-side part of the application (A1 - Chat Client) is usually known as front-end development. On the other side, developing the server-side part of the application (A3 - Chat Server) is known as back-end development.

Implementing the server-side of our chat protocol is not only a matter of properly supporting protocol messages, but also efficiently handling multiple connections. Due to the server being responsible for talking to several peers, whereas the client only has to talk to the server, we care more about performance in server-side development compared to its client counterpart.


Protocol#

The text-based protocol for the Chat Server is very similar to the one for the client. However, the server will now listen for client requests and send responses, instead of the other way around approach we used when implementing the client.

Note that every single protocol message should end with the \n terminator.

Server-side protocol#

The server-side protocol represents the set of messages sent by the server to the client, as responses to requests made by the client. The server should send these messages as responses to requests made by the client. The server shall never expect these messages to come from the client. Message parameters have been marked as [param].

Message formatDescriptionResponse to client message
HELLO [name]\nSecond hand-shake message. The server sends this if the handshake (i.e., log-in) is successful.HELLO-FROM [name]\n
IN-USE\nSent during handshake if the user cannot log in because the chosen username is already in use.HELLO-FROM [name]\n
BUSY\nSent during handshake if the user cannot log in because the maximum number of clients has been reached.HELLO-FROM [name]\n
LIST-OK [name1,name2,...]\nA list containing all currently logged-in users.LIST\n
SEND-OK\nA confirmation sent to the client that an outgoing message was sent successfully.SEND [name] [message]\n
BAD-DEST-USER\nThe destination user provided by [name] does not exist.SEND [name] [message]\n
DELIVERY [name] [message]\nRepresents the incoming message as a result of another client using the SEND protocol message.
BAD-RQST-HDR\nSent if the last message received from the client contains an error in the header.
BAD-RQST-BODY\nSent if the last message received from the client contains an error in the body.

Client-side protocol#

The client-side protocol represents the set of messages sent by the client to the server. The server shall listen for these requests and respond to them accordingly. The server should never send these types of messages as responses to the client. Message parameters have been marked as [param].

Message formatDescription
HELLO-FROM [name]\nFirst hand-shake message. The client sends this in an attempt to log in.
LIST\nRequest for all currently logged-in users.
SEND [name] [message]\nSend a chat message for a user with username name. Note that the message cannot contain the newline character, because it is used as the message delimiter

Specification#

The Chat Server specification defines additional capabilities on top of the protocol that the server should handle in its internal state. Unlike the client, the server will store the state of the application, keeping tack which users are logged in in some form of data structure.

If you haven’t already, this is the perfect time to start using the netcat command to test your implementation. Netcat enables direct interaction over TCP with the server, whereas the client requires you to go through the interface to send messages over the network.

The main advantage of netcat is automation; you can easily write some tests and put them in files, that you can easily redirect into netcat.

Server#

The following requirements define the capabilities the server should fulfill in order to acoomodate any client implementation.

  1. The server must fully implement the protocol defined above.
  2. The server must support at most 16 concurrent authenticated users. Once there are 16 authenticated users, the server should respond with BUSY\n to any other login attempts.
  3. The server must keep track of all authenticated users and remove those that have logged out by closing the connection.
  4. If the user tries to log in with a username containing any of the illegal characters !@#$%^&*, or spaces, the server shall respond with a BAD-RQST-BODY\n message.
  5. If a user tries to send any message but HELLO-FROM...\n before being authenticated, the server shall respond with a BAD-RQST-HDR\n message.
  6. If a user tries to send an empty message to another user, or a message only containing whitespaces, the server shall respond with a BAD-RQST-BODY\n message.
  7. The server must deliver messages only to the intended recipient.
  8. If a client tries to send an invalid protocol message, the server shall respond with a BAD-RQST-HDR\n message.
  9. If a client tries to send a valid protocol message containing an error in the body, such as a HELLO-FROM message missing the name, the server shall respond with a BAD-RQST-BODY\n message.

Technical#

The following technical requirements concern the implementation details of the server. Specifically, we limit some of the language capabilities used for educational purposes, as well as define a set of qualitative requirements for performant code.

  1. The implementation must not use either of the exit() or sendall() Python functions.
  2. The server must support multiple connections by means of threading or polling.
  3. To be considered performant and be eligible for bonus points for code quality, the implementation must use at most two threads, including the main thread.
  4. The be considered performant and eligible for bonus points for code quality, the server must receive data from the network in an efficient manner, by using the recv() function to its full performance potential.

To test your server, you will have to run multiple terminal windows, executing your previous Chat Client implementation, as well as your current Chat Server implementation. Instead of running the provided framework server, you will use your current implementation to test whether the Chat Client can communicate with other clients properly using your server.

Start by opening a new terminal and executing the server:

python3 -m a3_chat_server

It may be useful to use the Python logging package to add debug messages to your server, keeping track of incoming connections and data flow.

Continue by opening several new terminals and executing the client. If you kept the default host and port, the clients should connect automatically to the server. If not, make sure the server is listening on 0.0.0.0 at the same port the client is trying to connect to. Execute the client by running:

python3 -m a1_chat_client

Finally, once you think the server implements every interaction according to the specification, upload you code to CodeGrade to run the automated tests.