- Netzwerk-Programmierung erfordert die Definition von
- geeigneten Leitungen
- Übertragungsprotokollen
- explizite Befehle zum Senden und Empfangen
- kein Schutz von gemeinsamen Variablen erforderlich
Das Schema des Nachrichtenaustauschs ist in Abbildung
2
dargestellt.
Abbildung 2: Schema des Nachrichtenaustauschs
- Java bietet Kommunikation auf Basis von TCP/IP Sockets
- von praktisch allen Betriebssystemen unterstützt
- nahezu jede Treiber-Software von Netzwerk Hardware
bietet Unterstützung für TCP/IP
- Sockets sind aus Programmiersicht die
Software-Schnittstelle zum Netzwerk
- entsprechen etwa den Filehandles
- Java-Netzwerk-Support im Package java.net
- zusammen mit dem Package java.io
- und dem Package java.nio
- bietet eine oder mehrere Punkt-zu-Punkt Verbindungen
- 1-zu-n- oder m-zu-n-Verbindungsnetzwerke nur mit
zusätzlichem Aufwand bzw. Packages
Sockets
- Implementierung von Verbindungen mit
- Java Klassen ServerSocket und Socket
- Socket-Verbindung wird unsymmetrisch aufgebaut
- ein Ende (der Server Socket)
wartet auf Verbindungswunsch
- anderes Ende (der Client Socket)
versucht eine Verbindung aufzubauen
- wenn dies auf beiden Seiten gelingt
besteht ein zuverlässiger Verbindungskanal
- ab dann Senden und Empfangen möglich
Spezifikation von ServerSocket:
public ServerSocket(int port) throws IOException
public Socket accept() throws IOException
- Konstruktor ServerSocket erzeugt einen neuen
Server Socket an port
- bei Portnummer 0 an einem beliebigen freien Port
- Methode accept() wartet auf einen Verbindungswunsch
- gibt einen Socket für die Verbindung zurück
- blockiert bis eine Verbindung zustande kommt
Spezifikationen von Socket
public Socket(String host, int port)
throws UnknownHostException, IOException
public InputStream getInputStream() throws IOException
public OutputStream getOutputStream() throws IOException
- Konstruktor Socket erzeugt neuen Client Socket
- zu dem angegebenen host und port
- stellt Eingabe- und Ausgabe-Strom zur Verfügung
- Zugriff mit getInputStream() und getOutputStream()
- Strom (Stream) ist eine unformatierte und unstrukturierte Folge
von Daten
- an einem Ende werden Daten eingefüllt,
am anderen Ende erscheinen sie in der gleichen Reihenfolge
- InputStream und OutputStream
bestehen aus Folgen von Bytes
Abbildung E: UML Socket
Zuordnung von passenden Datenströmen:
- reine Unicode Zeichen mit Reader und Writer
- im folgenden ObjectStream
- Austausch beliebiger serialisierbarer ( serializable)
Objekte
- Umwandlung von Java-Objekten in einen Byte-Strom
- und typsicheres Versenden und Empfangen
- auch für Datei-Ströme verwendbar
- akzeptiert nur Objekte, die das java.io.Serializable
Interface implementieren
- ist eins der wesentlichen neuen Features von Java 1.1.
- auomatische Serialisierung überschreibbar
- dann muß man die Klasse selbst kodieren und dekodieren
- bei Filehandles keine Serialisierung sinnvoll
- Strom-Header enthält eindeutige Identifikation
der Objekt-Strom-Klasse
Spezifikation der benötigten Konstruktoren und Methoden
public ObjectOutputStream(OutputStream out) throws IOException
public void flush() throws IOException
public ObjectInputStream(InputStream in)
throws IOException, StreamCorruptedException
- Konstruktor ObjectOutputStream erzeugt neuen
Objekt-Ausgabestrom
- zu einem gegebenen OutputStream
- flush() verschickt Daten unmittelbar
- Konstruktor ObjectInputStream erzeugt neuen
Objekt-Eingabestrom
- zu einem gegebenen InputStream
- Passt die Identifikation nicht wird eine
StreamCorruptedException ausgelöst
- z.B. inkompatible JDK-Version, inkompatible Serialisierung
- blockiert, bis ein Objekt-Ausgabe-Strom die
entsprechenden Daten gesendet
Abbildung F: UML Serialization
Datenübertragung mit Send-Operation ( send)
und Empfangs-Operation ( recieve).
Spezifikation aus ObjectOutputStream
public final void writeObject(Object obj)
throws IOException
- writeObject() schreibt ein Objekt auf den
Ausgabe-Strom
- der gesamte Graph des Objekts wird zerlegt (serialisiert)
- und mit dem Klassennamen und Klassensignatur geschrieben
Spezifikation aus ObjectInputStream
public final Object readObject()
throws OptionalDataException,
ClassNotFoundException, IOException
- readObject() liest ein Objekt von dem
Eingabe-Strom
- der Klassenname und Klassensignatur wird gelesen
- der gesamte Graph des Objekts wird gelesen
- und rekonstruiert
SocketChannel
Der Konstruktor nimmt einen Socket als Eingabe und
setzt die Objekt-Ströme aus den entsprechenden Strömen auf.
Die Methode close() dient zum schließen des Kanals.
send()- und receive()-Methoden
dienen der Datenübertragung
import java.io.*;
import java.net.*;
public class SocketChannel {
private ObjectInputStream in;
private ObjectOutputStream out;
private Socket soc;
public SocketChannel(Socket s) throws IOException {
soc = s;
if (checkOrder(s)) {
in = new ObjectInputStream(s.getInputStream());
out = new ObjectOutputStream(
s.getOutputStream());
}
else {
out = new ObjectOutputStream(
s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
}
}
public void close() {
if (in != null) {
try { in.close(); } catch (IOException e) { }
}
if (out != null) {
try { out.close(); } catch (IOException e) { }
}
if (soc != null) {
try { soc.close(); } catch (IOException e) { }
}
}
private boolean checkOrder(Socket s)
throws IOException {
int p1 = s.getLocalPort();
int p2 = s.getPort();
if (p1 < p2) return true;
else if (p1 > p2) return false;
int a1 = s.getLocalAddress().hashCode();
int a2 = s.getInetAddress().hashCode();
if (a1 < a2) return true;
else if (a1 > a2) return false;
throw new IOException(); // this shouldn't happen
}
}
- die Reihenfolge der Erzeugung der Objekt-Ströme
out und in muß vertauscht sein
- da sich Objekt-Ströme bei dem
Verbindungsaufbau über die Verwendung der gleichen
Klassen und JDK-Versionen einigen müssen
- Methode checkOrder vertauscht
- auf dem gleichen Host sind die Ports verschieden,
sonst die IP-Adressen
Die Sende- und Empfangs-Methoden sind wie folgt.
public void send(Object v) throws IOException {
out.writeObject(v);
}
Im Fehlerfall wird eine
IOException ausgelöst,
die dann vom Aufrufer behandelt werden muß.
public Object receive()
throws IOException,
ClassNotFoundException {
return in.readObject();
}
Neben einer
IOException kann auch noch eine
ClassNotFoundException ausgelöst werden,
falls das Objekt zu einer dem Empfänger unbekannten Klasse
gehört.
Beispiel HelloWorld mit SocketChannel
Abbildung A1: HelloWorld
Implementierung:
HelloWorldClient.java
HelloWorldServ.java
SocketChannel.java
© Universität Mannheim, Rechenzentrum, 2000-2005.