Project Specification:

You may write the program in any language that is supported under any Integrated Development Environment (IDE). Keep in mind that available controls, objects, libraries, et cetera, may make some of these tasks easier in one language than in another.

This lab is intended to be built upon Lab 1. While it is not required that you reuse code from the first lab, most of the framework needed to implement this program should already be in place upon completing Lab 1.

All components should be managed with a simple GUI. The GUI should provide a way to kill the process without using the 'exit' button on the window.

You will implement an asynchronous message service consisting of a server process and three clients. Each client process will connect to the server over a socket. The server should be able to handle all three clients concurrently.

Clients will prompt the user for a username. When a client connects to the server, its username should be displayed by the server in real time. Two or more clients may not use the same username simultaneously. Should the server detect a concurrent conflict in username, the client's connection should be rejected, and the clients user should be prompted to input a different name.

The server will keep a cumulative log of previously used usernames and display those names on its GUI. The server should indicate which of those usernames represent clients presently connected to the server and which are not connected. Clients may reuse usernames and a client reusing an extant username should not be treated as a duplicate in the log.

When the server encounters a new username, a unique message queue should be created for that username. This queue may consist of any type of data structure, but an independent queue should exist for each name. This queue must be able to contain an arbitrary number of messages.

When a message is received by the server, the server should place the message in the corresponding queue for that intended recipient and mark that message with the time of its reception. Queues should be persistent (e.g., the contents should survive the server process restarting) even if there are no messages in that queue when the server process is killed.

When a client connects to the server, the user should be prompted to select one of two options:

  • Send message; or,
  • Check for messages.

If the user selects "Send message", the server should provide the log of usernames to the client. The user will then be prompted to select from one of three options:

  • Send message to specific username (1-to-1)
  • Send message to a subset of usernames (1-to-n)
  • Send a message to all usernames (1-to-all)

If a user selects options 1 or 2, it is the developer's discretion with regards to how the user indicates their selection. If the user indicates their selection by typing a string, the client should reject that string if it does not match an entry in the list received from the server.

Once the user has selected the intended recipient(s), the user should be prompted to enter a brief text message. When the user has finished, the text message should be uploaded to the server.

If the user selects "Check for messages", the server should deliver the contents of the message queue that corresponds to that client's present username. If the queue is currently empty, the user should be notified that no messages are available. Once messages are retrieved by the client, the server should delete them from the queue.

The client should remain connected to the server until manually disconnected by the user. The required actions are summarized below.

Client

Startup:

  • Prompt the user to input a username.
  • Connect to the server over a socket and register the username.
    • When the client is connected, the user should be notified of the active connection.
    • If the provided username is already in use, the client should disconnect and prompt the user to input another username.
  • Proceed to send and check for messages until manually killed by the user.

Sending Messages:

  • The client will present the list of usernames received by the server to the user.
  • The user will be prompted to select from one of the three messaging options listed above.
  • The user will be prompted to select their intended recipient(s).
  • After the recipients are selected, the user should be prompted to input a brief text message.
  • The client will upload the text message to the server.
  • Return to Sending Messages: Step 1 until manually disconnected by the user.

Checking Messages:

  • When connected to the server, the client will indicate it wants to retrieve messages from its message queue.
  • If the clients message queue is not empty:
    • The client will retrieve all text messages addressed to it; and,
    • Print the content of those text messages to its GUI.
    • The text message should indicate from which username the message was received and a timestamp of when that message was received by the server.
  • Return to Receiving Messages: Step 1 until manually disconnected by the user.

Server

The server should support three concurrently connected clients. A cumulative log of all previously used usernames should be maintained by the server and presented on the server's GUI. The server should indicate which of those usernames (if any) represent currently connected clients. The server will execute the following sequence of steps:

  • Startup and listen for incoming connections.
  • Print that a client has connected, log the client's username, and:
    • If the client username is available (e.g., not currently being used by another client), fork a thread to handle that client. Or,
    • If the username is in use, reject the connection from that client.
  • If a client name has not been encountered in the past, a new message queue for that client should be instantiated.

The server will proceed according to whether the client wants to send or check for messages.

  • If a client indicates it wants to send a message:
    • The server should provide the log of usernames to the client;
    • The server should accept messages from the client and place those messages in the intended client(s) message queue;
    • Received messages should be marked with a timestamp.
  • If a client indicates it wants to check for messages:
    • The server should send any available messages to the client; or,
    • Indicate that no messages are available.
    • Any messages delivered to the client should be removed from the persistent message queue.
  • Begin at step 2 until the process is killed by the user.

Notes:

  • All three clients and the server may run on the same machine.
  • The server must correctly handle an unexpected client disconnection without crashing.
  • When a client disconnects from the server, the server GUI must indicate this to the user in real time.
  • The program must operate independently of a browser.
Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.