Weitere aktuelle Java-Titel finden Sie bei dpunkt.
 Inhaltsverzeichnis   Auf Ebene Zurück   Seite Zurück   Seite Vor   Auf Ebene Vor   Eine Ebene höher   Index


19.2.3

Beispiel: Chat-Server



Am Beispiel eines Chat-Servers wird nun demonstriert, wie man mit RMI durch die Verwendung von Callback-Objekten eine asynchrone, bidirektionale Kommunikation realisieren kann. Die Chat-Anwendung besteht insgesamt aus drei Typen von Server-Objekten, wobei zwei der Typen auf dem Chat-Server und ein Typ auf dem Client als Callback-Objekt benutzt werden. Analog zur Kaufhaus-Anwendung gibt es auch beim Chat-Server auf Serverseite ein zentrales Server-Objekt, das dazu benutzt wird, sich beim Server anzumelden und somit neue Sitzungen zu erzeugen, sowie ein sitzungsorientiertes Objekt, das für jeden Client den aktuellen Sitzungszustand speichert. Zum aktuellen Sitzungszustand gehört in diesem Fall der Nickname des Benutzers und das Callback-Objekt, unter dem Nachrichten asynchron zu einem einzelnen Client geschickt werden können.

Das Erzeugen einer neuen Sitzung wird auf Serverseite über die Methode createSession durchgeführt:
  public ChatSession createSession(String nickname, 
                                   ClientHandle handle) 
                                    throws RemoteException {
    System.out.println("create session: "+nickname);
    ChatSession s;
    s = new ChatSessionImpl(this, nickname, handle);
    sessions.add(s);
    return s;
  }
Der Client übergibt dieser Methode den Nickname für die Sitzung und einen Verweis auf das Callback-Objekt, unter dem er Daten vom Server empfangen kann. Über das zurückgelieferte ChatSession-Exemplar kann der Client neue Nachrichten an alle aktuell verbundenen Clients schicken. Alle aktuell verbundenen Clients werden im zentralen Server-Objekt in einem List-Exemplar gespeichert.

Auf Client-Seite übernehmen folgende Zeilen den Aufbau einer neuen Verbindung:
  ChatServer server;
  server = (ChatServer)Naming.lookup("chat-server");
  handle = new ClientHandleImpl(this);
  session = server.createSession(nickname, handle);
Der einzige Unterschied zu einem herkömmlichen Aufruf ist, dass es sich bei der Klasse ClientHandleImpl selbst wiederum um ein Server-Objekt handelt, das in der Lage ist, Anfragen über Netzwerk entgegenzunehmen. Diese Eigenschaft bekommt die Klasse nur dadurch, dass sie von UnicastRemoteObject abgeleitet ist. Somit bekommt der Chat-Client eine Referenz auf den Chat-Server über den Namensdienst. Der Chat-Server bekommt ein Callback-Objekt des Chat-Clients durch die Übergabe als Parameter.

Wenn ein Client eine neue Nachricht zum Server schickt, wird diese Nachricht durch die Methode postMessage() im zentralen Server-Objekt verteilt:
  public void postMessage(String message, ChatSessionImpl s) {
    ChatSessionImpl tmp;
    for(int i=0; i < sessions.size(); i++) {
      tmp = (ChatSessionImpl)sessions.get(i);
      try {
        ClientHandler handle = tmp.getClientHandle();
        handle.receiveMessage(s.getNickname(), message);
      } catch(RemoteException ex) {
        System.out.println("unabled to contact client " 
                           + s.getNickname());
        System.out.println("removing.");
        removeSession(tmp);
        i--; // Da nun alle Clients in Liste einen  
             // Platz nach unten rutschen ...
      } 
    }
  }
Dabei wird die Liste mit allen aktuell verbundenen Clients sequenziell durchgegangen und durch Aufruf der Methode receiveMessage() des clientseitigen Callback-Objekts verschickt.

Material zum Beispiel

Distributed-Garbage-Collection (DGC)

Die automatische Freigabe von nicht mehr benötigtem Speicher vereinfacht in Java viele Aufgaben und macht den Code weniger fehleranfällig. Von der automatischen Speicherfreigabe wird aber nicht nur in lokalen Anwendungen Gebrauch gemacht, sondern auch in verteilten Anwendungen, die mit RMI entwickelt wurden. Hierbei gilt grundsätzlich dasselbe Prinzip wie bei lokalen Anwendungen auch: Server-Objekte, die nicht mehr referenziert werden, werden aus dem Speicher gelöscht.

Server-Objekte, die bei einem Namensdienst registriert sind können dabei nicht freigegeben werden, da der Namensdienst jederzeit eine Referenz auf das Server-Objekt hält. Deshalb ist die Freigabe im wesentlichen auf sitzungsorientierte Objekte beschränkt, die nicht direkt bei einem Namensdienst angemeldet werden (z. B. die ChatSession-Exemplare des Chat-Servers im vorangegangenen Abschnitt. Da diese Sitzungs-orientierten Objekte nur einem einzigen Client zugeordnet sind, werden sie nicht mehr benötigt, sobald der Client beendet wurde. Deshalb werden sie in solch einem Fall automatisch vom Distributed Garbage Collector freigegeben.

Wie schnell der Garbage Collector merkt, dass ein Objekt nicht mehr referenziert wird, hängt von der Einstellung der Property java.rmi.server.dcg.leaseValue ab. Per Voreinstellung ist diese Property nicht gesetzt, was einem Wert von 10 Minuten entspricht. Wenn es erforderlich ist, Ressourcen schneller wieder freizugeben, kann dieser Wert explizit angegeben werden, z. B. beim Starten der Java-Laufzeitumgebung. Bei folgendem Aufruf wird der Wert auf 30 Sekunden gesetzt (Angabe in Millisekunden):
java -Djava.rmi.server.dcg.leaseValue=30000 ShopServer
Man sollte beachten, dass mehr Kommunikationsaufwand erforderlich ist, wenn der Wert klein ist, da der Garbage Collector in diesem Fall öfter prüfen muss, ob die Server-Objekte noch erreichbar sind.

Die Implementierung des Interface Unreferenced ermöglicht es einem Server-Objekt, selbst darüber informiert zu werden, wenn es nicht mehr referenziert wird und somit aus dem Speicher gelöscht wird. Dieses Interface definiert lediglich die Methode unreferenced(). In dieser Methode können z. B. Ressourcen freigegeben werden, die nicht mehr benötigt werden (z. B. offene Datenbankverbindungen). Im Beispiel der Chat-Anwendung wäre es denkbar, über diesen Mechanismus die serverseitigen Verweise auf einzelne Clients in der internen Liste zu löschen:
  public void ChatSessionImpl extends UnicastRemoteObject 
                            implements ChatServer, Unreferenced {
    ChatServer server; 

    ...

    public void unreferenced() {
      server.removeSession(this);
    }
  }


 Inhaltsverzeichnis   Auf Ebene Zurück   Seite Zurück   Seite Vor   Auf Ebene Vor   Eine Ebene höher   Index

Copyright © 2002 dpunkt.Verlag, Heidelberg. Alle Rechte vorbehalten.