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


13.2.5

Erweiterbare Sockets



Seit dem JDK 1.1 ist es möglich, direkt von den Klassen Socket und ServerSocket Unterklassen abzuleiten und somit Sockets mit bestimmten Eigenschaften zu erzeugen. Mit dieser Methode kann man das Gleiche erreichen wie durch die Implementierung der Klassen SocketImpl und SocketImplFactory. Allerdings muss bei der Implementierung der Klasse SocketImpl die komplette Funktionalität eines Sockets bereitgestellt werden. Durch die Bildung von Unterklassen kann schon vorhandener Code wiederverwendet werden. Es ist nur notwendig, die Methoden neu zu implementieren, die tatsächlich geändert werden. Es ist z. B. möglich, dass nur die Ein- und Ausgabe-Streams bei den Sockets modifiziert werden müssen, um eine bestimmte Funktionalität zu bekommen.

Eine Möglichkeit, diesen Effekt zu erreichen, besteht darin, die Standard-Sockets weiterzuverwenden und die von getOutputStream() und getInputStream() gelieferten Streams sofort durch Filter-Streams zu erweitern. Dieser Vorgang müsste aber an jeder Stelle des Programmes vorgenommen werden, an der diese Funktionalität benötigt wird.

Als zweite Möglichkeit kommt das Ableiten einer Unterklasse von Socket in Frage. In diesem Fall kann man die Methoden getOutputStream() und getInputStream() so überschreiben, dass der von diesen Methoden zurückgelieferte Stream schon die gewünschte Funktionalität besitzt. Durch diese Technik müsste man nur einmal im Quellcode einen Filter-Stream erzeugen. Im folgenden Beispiel wird diese Technik zur Erzeugung von Sockets verwendet, die eine On-the-fly-Komprimierung durchführen.

Ableiten von Socket

Das Ableiten einer Unterklasse von Socket funktioniert eigentlich genauso wie bei jeder anderen Klasse auch. Folgende Klasse CompressedSocket ist von der Klasse Socket abgeleitet:
  public class CompressedSocket extends Socket {
  
    public CompressedSocket(String host, int port)
                   throws IOException, UnknownHostException {
      super(host, port);
    }
  
    public CompressedSocket() throws IOException {
      super();
    }
  
    public InputStream getInputStream()
                                 throws IOException {
      return new CompressedInputStream(
                                super.getInputStream());
    }
  
    public OutputStream getOutputStream()
                                 throws IOException {
      return new CompressedOutputStream(
                                super.getOutputStream());
    }
  }
Das Einzige, was bei dieser Implementierung geändert wurde, sind die Methoden getInputStream() und getOutputStream(). Sie wurden so modifiziert, dass sie die Streams, die von der Standardimplementierung zurückgeliefert werden, automatisch in komprimierende Streams ändern. Die eigentliche Implementierungsarbeit liegt also in den verwendeten Streams versteckt. Die Socket-Klasse selbst dient in diesem Fall nur als Vermittler. Da jeder Stream von InputStream bzw. OutputStream abgeleitet ist, kann der Benutzer dieser Socket-Klasse auf die Streams genau auf die gleiche Art und Weise zugreifen, wie auf die Streams eines Standard-Sockets.

Die hier verwendeten Streams CompressedInputStream und CompressedOutputStream sind nicht in den Standardklassen des JDK enthalten. Sie wurden jedoch mit den Mitteln des JDK 1.1 programmiert. Sie arbeiten jeweils auf der Basis von bestimmten Paketgrößen. CompressedInputStream transportiert die eingegebenen Daten nicht sofort zum Empfänger, sondern puffert Daten, bis sich eine bestimmte Menge angesammelt hat. Dann werden die Daten komprimiert und verschickt. Auf Server-Seite muss sich natürlich auch ein Socket befinden, der die komprimierten Daten dekomprimieren kann. Das ausführliche Listing ist auf der CD enthalten.

Ableiten von ServerSocket

Das Ableiten einer Unterklasse von ServerSocket kann im Prinzip genauso einfach durchgeführt werden. An dieser Stelle wird ein Server-Socket betrachtet, der als Ergebnis des accept()-Aufrufs einen anderen als den Standard-Socket-Typ zurückliefert. Folgender ServerSocket besitzt die Eigenschaft, Sockets vom im letzten Abschnitt definierten Typ CompressedSocket zurückzuliefern:
  public class CompressedServerSocket
                            extends ServerSocket {
  
    public CompressedServerSocket(int port)
                              throws IOException {
      super(port);
    }
  
    public Socket accept() throws IOException {
      CompressedSocket s = new CompressedSocket();
      implAccept(s);
      return s;
    }
  }
Wie man dem Beispiel entnehmen kann, ist es nur notwendig, die Methode accept() neu zu implementieren. Der erste Schritt, der hier unternommen wird, ist das Erzeugen eines neuen Exemplars des Sockets, das zurückgeliefert werden soll. Für diesen Zweck benötigt die Klasse Socket einen Konstruktor ohne Parameter, da der Socket zu dieser Zeit noch nicht mit einem bestimmten Rechner verbunden werden soll. Anschließend wird die Methode implAccept(Socket) aufgerufen, und zwar mit dem Socket-Exemplar als Argument. Beim Aufruf von implAccept(Socket) wird die Programmausführung so lange unterbrochen, bis eine Verbindungsanforderung von einem anderen Rechner eingetroffen ist. In diesem Fall wird der implAccept(Socket) übergebene Socket mit dem anfordernden Rechner verbunden. Nach der Ausführung von implAccept(Socket) wird der Socket durch Aufruf als Funktionsergebnis von accept() zurückgegeben.

Dieser ServerSocket stellt das Pendant zu dem im letzten Abschnitt beschriebenen CompressedSocket auf Server-Seite dar. Die Klasse CompressedSocket alleine kann nur auf Client-Seite verwendet werden. Sie besitzt nur die Möglichkeit, Verbindungen zu einem bestimmten Server aufzubauen. Allerdings muss auf Server-Seite auch ein Socket zur Verfügung stehen, der die Komprimierung vornehmen kann. Diese Aufgabe wird von dem hier beschriebenen CompressedServerSocket übernommen. Dadurch, dass auch die Server-Seite über das Ableiten von ServerSocket einen CompressedSocket verwenden kann, ist die Komprimierung und Dekomprimierung sowohl auf Client- als auch auf Server-Seite möglich.

Neben dem hier vorgeführten Beispiel der Datenkompression können natürlich auch andere Eigenschaften eines Sockets verändert werden, wie z. B. die Datenverschlüsselung.


 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.