Project 4 - Distributed Chat Application using Java RMI

Due April 4, 6:00PM

Your task is to implement a Java client for a chat server. A chat server allows clients to broadcast messages to other clients that have joined in the chat session (called peers). The twist is that the chat server is effectively distributed among all the clients that are currently running, with a central server used mainly to bootstrap a client that wants to join the chat session, so that the client can find one (or several) other clients. This project is intended to impart some of the the flavor of Gnutella. All communication is done via remote procedure calls, using Java Remote Method Invocation (RMI).

The general idea is that each client only communicates with a small set of peers, but that set is determined by the central server. A client is then responsible for forwarding all messages it receives to all peers it knows about (except the one that sent it the message). The peer set may change while the client is running, either because the central server decides to change the set, or because the client decides that it needs a new set of peers. We will describe the conditions under which a client makes that decision later.

When a client starts up, it must connect to the central server, as specified on the command line, and request a set of clients that it will communicate with. After this initialization, the client can broadcast messages (via RMI to its peers) and receive messages (again via RMI calls) from its peers. The client must implement several public methods to communicate with the central server, and several public methods to communicate with other clients. The interface for the client is:

public interface LocalClient {
	public void initialize(Directory s)  throws java.rmi.RemoteException;
	public void initiateMessage(String msg);
	public void addMessageListener(MessageListener l);
	public void removeMessageListener(MessageListener l);
	}

public interface RemoteClient extends java.rmi.Remote {
	public void msg(Message m) throws java.rmi.RemoteException;
	public void newPeers(RemoteClient[] peers) throws java.rmi.RemoteException;
	public void ping() throws java.rmi.RemoteException;
	}

public interface MessageListener extends java.util.EventListener {
	public void message(String m);
	}

A sample driver for your client code is in ClientDriver.java . The driver connnects to a central server, initializes the local client (ClientImpl is the class you will write that implements the LocalClient and RemoteClient interfaces), and then communicates with the central server to find out about its peers (i.e. the initialize(server) call). The driver then broadcasts a message every 5 seconds via LocalClient.initiateMessage() (which does an RMI call to the client's peers via the RemoteClient.msg() method), with the message data read from System.in .

Javadoc commentary for the project is available. You can access the templates and drivers for the project from ~asussman/Projects/p4 on the cluster, and the templates are also contained in this jar file.

Details

One problem to watch out for is to make sure a client does not forward a message it has already seen. That means all messages must be have some unique identifier (e.g., the originating client ID and a message sequence number for that client), and a client must check each incoming message against all prior messages that it has sent out.

As shown in the RemoteClient interface, clients must also support the ping() method, that can be used by either the central server or another client to determine whether a remote client is still alive. Note that in this system clients can join and leave independent of all other clients at any time. So the central server and each client needs to be able to determine periodically whether or not a particular client is still alive. Similarly, the client must support the newPeers() method, to allow the central server to change the set of peers a client communicates with.

Web Accessibility