CSCI A348/A548

Lecture Notes 25

Fall 1999


Developing a standalone chat server and client using Java RMI

As you remember, in class we discussed homework assignment #7. We produced a complete solution for it. I will post a summary of our discussion here after the holiday, except I do not indend to post any code (like we did in class) so you'd have to rely on your notes. I will post however the story of the complete development process such that if you look at the lecture notes posted for last Thursday's lecture (lecture notes 24, with basic RMI) and the story below (to be posted when we come back from the holiday) you should be able to solve the problem with no difficulty.

Here then is the whole story:

How I spent my Thanksgiving Holiday implementing a standalone distributed application in Java (wity RMI) that acts as a chat client-server application.

I decided to follow the RMI recipe. So I first wrote the interface for the server and the interface for the client. These interfaces describe the methods that each one is ready to make available to interested parties (essentially to one another) over the network. The server has two such methods: So here's what the server should be exporting:
import java.rmi.*;

public interface ServerExports extends Remote {
  public void register(ClientExports client) throws RemoteException; 
  public void broadcast(String message) throws RemoteException; 
}
And here's what the client should be exporting:
import java.rmi.*;

public interface ClientExports extends Remote {
  public void update(String message) throws RemoteException; 
}
Now that I have these two interfaces I decide to implement them.

First the server:

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*; 

public class Server 
  extends UnicastRemoteObject 
  implements ServerExports 
{
  Vector chatters = new Vector(); 

  public Server() throws RemoteException {
    System.out.println("Initializing server..."); 
  } 

  public void register(ClientExports c) throws RemoteException {
    chatters.addElement(c); 
  } 

  public void broadcast(String message) throws RemoteException {
    for (int i = 0; i < chatters.size(); i++) { 
      try { 
        ((ClientExports)(chatters.elementAt(i))).update(message); 
      } catch (Exception e) {
        System.out.println("Client unavailable..."); 
      } 
    }
  }

  public static void main(String[] args) {
    Registry reg; 
    System.setSecurityManager(new RMISecurityManager()); 
    try {
      Server s = new Server(); 
      reg = LocateRegistry.createRegistry(Integer.parseInt(args[0])); 
      reg.bind("Melville", s); 
      System.out.println("Server ready..."); 
    } catch (Exception e) {
      System.out.println("Error: " + e); 
    } 
  }   

}
Then the client:
import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
 
public class Client implements ClientExports {

  String name; 

  public Client(String name) throws RemoteException {
    System.out.println("Starting up client..."); 
    this.name = name; 
  }  

  public void update(String message) { 
    System.out.print(message); 
  } 

  public static void main(String[] args) {
    ServerExports SE; 
    Client c; 
    if (args.length <= 0)  {
      System.out.println(
        "Call client with:\n" +
        "        java Client [name] [serverHost] [serverRMIPort]\n\n" +
        " as in  java Client Larry tucotuco 39904\n" 
      ); System.exit(0); 
    } 
    try {
      c = new Client(args[0]); 
      UnicastRemoteObject.exportObject(c); 
      SE = (ServerExports)Naming.lookup(
              "rmi://" + args[1] + 
              ".cs.indiana.edu:" + 
              args[2] + "/Melville"
      );
      SE.register(c); 
      SE.broadcast("***(" + c.name + ")*** has just connected.\n"); 
      c.talk(SE); 
    } catch (Exception e) {
      System.out.println("Client: error in main..." + e); 
    } 
  } 

  public void talk(ServerExports SE) {
    try { 
      InputStreamReader reader = new InputStreamReader(System.in);
      BufferedReader    b      = new BufferedReader   (reader); 

      String            line   = b.readLine(); 

      while (! line.equals("quit")) { 

        System.out.println("You typed: " + line);      

        SE.broadcast(name + "> " + line + "\n"); 

        line = b.readLine(); 

      }      
    } catch (Exception e) {
      System.out.println("Client: error in talk..." + e);       
    } 
  } 
} 
Now that I have them all I compile them with javac and run rmic on the server and client class (not interfaces). Then (after I make sure that I am connected to my assigned host (tucotuco) I start the server on the registry port that I have been assigned (39904).

Now I open several connections with other hosts on the burrow cluster and in each one I start the client software with different names in the command line but with the same information on the server host (my host) and registry port number (my registry port number). And I can start and conduct a chat session between the three clients.


Last updated: November 30, 1999 by Adrian German