Project 4: Simple Chat Server


Category: You will Instantly receive a download link for .zip solution file upon Payment


5/5 - (2 votes)

This project is separated into 6 parts that you have to complete:
Part 0: Running and Understanding the Skeleton Code
Part 1: Making the Connections Persistent
Part 2: Taking Client Input and Sending to Server
Part 3: and Tying it Together
Part 4:
Part 5: Direct Messaging, Tic Tac Toe, and Listing Users
Introduction to the Client-Server Architecture
Overview: The Client-Server Architecture is an extremely common design for applications these
days. The basis of the design is that there is one server that processes received data and sends
data to multiple clients. The server spawns threads for each client that joins. Those threads
then wait for the client to send a message to the server.
In this project, the Client is designed to be independent of the Server, meaning the Server
contains no dependencies with the Client. You will be communicating from the Client to the
Server through a serializable object. A serializable object is an object that has been converted
to a byte stream that is then able to be sent across a connection where it is then deserialized
into a copy of the original object. You do not need to implement the serialization.
The server plays a crucial role in the client-server architecture. What the server does is it waits
until a client attempts to join a network with identical port numbers. In our case the “network”
will be “localhost” and the port will be 1500. “localhost” is a special input that specifies that
the client Sockets and the server ServerSocket are all hosted on one local machine.
A modern day example of the client-server architecture is a network connection. The router
acts as the server, which parses data to be sent into the internet, and your device that is
connected to the network is the client. Your device acts independently from other devices on
the network. That is unless you are using shared resources. Think how Google Docs works.
There are multiple devices writing to one file. From previous labs you know that if these clients
aren’t threaded properly, the Google Doc would be unreadable from all of the race conditions
that are occurring. These race conditions happen because the threads are not synchronized
meaning that they will read and write to the file regardless of it corrupting the data.
Activity Diagram of Project 4
Part 0 – Running and Understanding the Skeleton Code
Part 0 overview:
The skeleton code that you have been provided will run (see here for the demo). It does no
error handling, user input, message formatting, nor will it persist the connection from server to
client. Once the server is started, it will wait for a client to connect and send their username.
The server will then print the username and the word “ping”. To notify the client that it has
received its username, the server then sends back the word “pong”. Below is a clearer table of
what is happening.
1 Server is started and waits for a client
2 Client is created and connects to the
server and sends a string as its username
3 Server prints username + “ping”
4 Server sends back “pong” and ends
5 Client receives “pong” and prints it and
ends the program
Questions to ponder when reading the Skeleton code:
● Why do we need to start the server before starting the client?
● How are the messages being sent from the server to the client and vice versa?
Part 0 notes:
What are ArrayLists:
An arraylist is a dynamic data structure. Dynamic means that it adapts as data is added to it or
removed from it.
To initialize an ArrayList you do the following:
ArrayList dynamic_array = new ArrayList<>();
The word Type is a java object that the list contains. So if the Type was String , you would have
an ArrayList of strings.
To add to an Arraylist use the add method. To remove, use the remove method. To get the size
use the size method. To get an element use the get method.
For further explanations and details see the javadoc for ArrayList.
Part 1 – Making the Connections Persistent
Part 1 overview:
Right now when you run the skeleton code you will notice that the client sends a message to
the server and then both the client and the server close their connections to each other. Your
goal is to make those connections persist so multiple messages can be sent without restarting
the server and the client.
Part 1 details:
In order to for the server to persist forever, you need to make the program run forever.
To do this you will need to implement an infinite loop that indefinitely accepts clients
while(true) {
Socket socket = serverSocket.accept();
// server waits until a client opens a Socket with the same address and port number
Once this is implemented, the server will run indefinitely. But the client still doesn’t persist after
the “pong” message is sent from the server to the client. Once again you will need to
implement an infinite loop that listens for the server to broadcast messages to the clients.
In the ListenFromServer class’s run method, you will need to put the infinite loop there. This
method will continue to run
Part 1 demonstration:
Once implemented correctly, your server and client should behave like below. Note that the
program does not end after printing these messages.
Part 2 – Taking Client Input and Sending to Server
Part 2 overview:
In order for the chat server to be useful, there needs to be chat functionality. In your main
method for the ChatClient class you need to be able to take in parameters like username,
server address, and port number.
Example: in terminal (or IntelliJ configuration)
java ChatClient username portNumber serverAddress
The example above assumes:
● username is an alphanumeric string with no spaces.
● portNumber is a numeric value.
● serverAddress is the ip address of a server or can be “localhost” if unspecified.
Below are the following formats of parameters that need to be handled:
java ChatClient [username] [portNumber] [serverAddress]
java ChatClient [username] [portNumber]
java ChatClient [username]
For the server, the parameters passed should follow the format below:
java ChatServer [portNumber]
java ChatServer
Fill in the missing parameters with “1500” if portNumber is not specified, and “localhost” if
serverAddress is absent.
Now that parameters are dealt with, we will move onto the chat functionality.
Implementing the chat functionality will be done in the main method of the ChatClient class.
There you will need to:
1. Implement a way to read in user input from terminal after the ChatClient object has
been started.
2. Parse the user input to determine the type of message.
3. Send the message with the sendMessage(ChatMessage msg) method (more detail in
part 3)
4. Repeat from step 3.
Now you have chat functionality. One more thing though, you need to also implement a way for
users to logout from the chat server.
To handle this you need to:
1. Check if the user inputs “/logout” (case insensitive).
2. Close the client’s ObjectInputStream, ObjectOutputStream, and the Socket.
The server will handle the logout in the next part.
Part 3 – and Tying it Together
Part 3 overview:
In this part you will define the basic attributes of the ChatMessage class. Right now, all you
should see is private static final long serialVersionUID = 6898543889087L;
This is how you will serialize your messages, effectively keeping the client separate from the
server. In basic terms, serialization is the process of converting an object with data into
bytecode where it is then transmitted across a network connection and reconstructed as a copy
on the server’s side. You will not have to implement the serialization, but you will create the
rest of the ChatMessage.
The constructor will need to take in an integer and two Strings.
The integer determines the type of message that will be sent. The types of messages that can
be sent are 0 which is a general message (nothing special), 1 which is a logout message, 2 which
is a direct message between users, 3 which is a request for the list of clients, and 4 is a request
to start a TicTacToe game with another user. The logout message, when reconstructed in the
server, will let the server know who logged out.
The first String is the message that will be sent from the client to the server, and the second
String is the recipient of the message. If the message is not a direct message or a game
command, the recipient field can just be an empty String.
You will need to add getters to get the type, the message, and the recipient of a ChatMessage
Now that the client has the option to logout and send messages we need to handle that in the
server. To do that you will implement the following methods:
● private void broadcast(String message)
○ The broadcast method will be shared across all clients so this method will need
to use concurrency. This is up to you how to implement this. The method will
then print the message to terminal of every client. This will be done by iterating
through the client list and writing the message using the writeMessage(String
msg) method. You will also need to print the message to the server’s terminal
with a simple print statement.
○ When broadcasting the message to the server and the clients, add the date and
time when the message was sent. Do this with SimpleDateFormat using the
format “HH:mm:ss”.
● private boolean writeMessage(String msg)
○ This method will need to be implemented in the ClientThread class inside of the
ChatServer class. writeMessage will return false if the socket is not connected
and true otherwise. Before returning true, make sure you actually write the
message to the ClientThread’s ObjectOutputStream using the writeObject
method from the ObjectOutputStream class.
● private void remove(int id)
○ The remove method will take an integer as input that is used to determine which
client to remove from the clients ArrayList. This method will also be shared
across every client thread, so once again you will handle the concurrency here.
● public void run()
○ The run method is partly implemented already and is located in the ClientThread
class. What you need to do is to handle the ChatMessage cm by checking which
type cm is and handling it appropriately based on the type. You will then
broadcast the message to the server in the format: username + “: “ + message
● private void close()
○ This method does the exact same as logging out in the ChatClient class, but for
the socket connection from the server to this client.
At this point your server is almost done. Now you need to do some error handling.
Think of ways your server can break.
Think along the lines of “What happens when I start a client before starting the server?”
Also note that usernames are case insensitive and unique so there cannot be two names that
are the same.
Part 4 –
Part 4 overview:
Now that you have your server and chat up and running, let’s add something fun for users to do
while connected! We are going to be implementing a small Tic Tac Toe engine into the server.
Tic Tac Toe is a fairly simple game. It takes place on a 3×3 board of spaces where the two
players alternate placing their respective character, X or O, into an open space. The goal of the
game is to get three Xs or three Os in a row while, at the same time, preventing your opponent
from achieving the same thing.
Sample Tic Tac Toe Boards
0 | 1 | 2 X | O | X
———— ————-
3 | 4 | 5 X | O | O
———— ————-
6 | 7 | 8 | X |
With the game in mind, you will be implementing a way for users to play matches of Tic Tac Toe
with each other through the Client-Server connection.
Users will play with the /ttt command as follows:
To start a game against a player: /ttt /ttt Anna
To make a move in a game: /ttt /ttt Anna 3
To view a current game’s board: /ttt /ttt Anna
Some notes:
● The player that starts the match with /ttt will be player X. The is player O.
● Players cannot start matches with themselves.
● Assume a new game cannot start with the same player until the previous game finishes.
● Players may participate in as many matches as there are current players simultaneously.
● Players should not be able to play out of turn (like twice in a row!)
● A message should be outputted to both players when a game of Tic Tac Toe is started or
● The board should be shown to both players after one of them makes a move.
● Make use of return values from your methods. For example, return a negative number
if something fails. You can even return different negative numbers for different failure
cases (this is useful in testing!)
Some other things to think about:
● How should the server handle making a move against a disconnected player?
● What if that disconnected player reconnects?
● Where should the games be stored? Globally by the Server? In the Client threads?
○ (Pick a method that makes sense to you!)
● Where is the game input processed? Server side or client side?
● What controls creating and ending the games of Tic Tac Toe? If TacTacToeGame is the
game itself? (The server probably needs to process this!)
You may wish to look at the provided directMessage code in the skeleton to get some ideas on
how you want to handle the Tic Tac Toe games and user input for them. Direct Messaging
works similar to the server’s broadcast function but only sends its output to a single user.
Suggested methods in
Name Return Type Parameters
TicTacToeGame() – String otherPlayer, boolean isX
takeTurn() int int index
getWinner() char –
isTied() int –
getSpace() double int index
toString() String –
Feel free to implement additional methods if you think they may be helpful to you.
Server-side, you probably want some way to start a game, process a turn, and end a game.
Part 5 – Listing Users
Part 5 overview:
Listing Users
Your server should also have the ability to list the users that are currently connected to the chat
server. The format for this command will be:
This command will print the names of the users who are connected to the server excluding the
user who typed the /list command.
For a demonstration of expected server-client behavior, please see the video demo provided
Turning in Your Work
Submit the following to Vocareum prior to the due date:
Team Review
After the assignment due date, you will be requested to provide us with feedback for how you
and your peer worked as a team. More details for this will be given nearer the due date.
Grading will occur in lab the week after the due date and will be purely manual. At least one of
your teammates must be present for questions regarding the program (there will still be a lab
assignment, as usual).
The grading rubric is on the following page.
Task Points
A user can join the server and is greeted with a welcome message from
the server.
User can send a chat message and all other users will receive it. 10
The user can send a chat message and the server receives it. 7
The user receives an error attempting to join if the server is not running. 3
Multiple clients can join the server at one time. 10
The client and server persist after one command. (i.e. they run forever) 10
Users can logout using /logout. The server then broadcasts that the user
has logged out. (The client list is updated)
The server should not disconnect unless the server is stopped in
terminal (Ctrl-C)
Two clients cannot join with identical usernames. 7
Direct messaging works with two separate clients. Direct messaging
works with two or more separate clients. (a client cannot direct message
/list command list the users in the current chat server excluding the user
who typed the command. /list command lists the users in the current
chat server excluding the client who typed the command.
Users can play Tic Tac Toe with each other. 7
Tic Tac Toe games won’t start if they are already in progress, and will
end properly.
The format of output is similar to the demonstration. (including the
simple date format)
There should be no race conditions when sending messages to the
server or disconnecting users.
Team Review 5