Warum Socket-Programmierung?
Sobald man Programme schreiben will, die nicht auf einem einzigen Rechner gespeichert
sind, sondern auf mehrere beliebige Standorte, die miteinander vernetzt sind,
verteilt sein können, muss man sich Gedanken darüber machen, wie die
einzelnen Programmteile miteinander kommunizieren können. Eine schon recht
alte, aber immer noch häufig verwendete Methode ist die Kommunikation über
Sockets. Hierbei agiert das Programmteil, das einen Dienst anbietet als Server,
das andere als Client.
Java stellt mittlerweile einige recht komfortable Klassen zur Socket-Programmierung
zur Verfügung. Das Package java.net enthält die folgenden
zwei Socket-Klassen:
- ServerSocket
- Socket (hiermit ist immer der Client-Socket gemeint)
Neben den Socket-Klassen benötigt man für die Kommunikation über
Streams folgende zwei Stream-Klassen aus dem Package java.io:
Mit diesen zwei Klassen lassen sich allerdings nur Interger-Zahlen übertragen.
Falls man beliebige Objekte mit Streams übertragen möchte, braucht
man aus java.io auch noch:
- ObjectOutputStream
- ObjectInputStream
Das Einleiten vom Aufbau einer Socket-Verbindung ist immer die Aufgabe des
Clients. Solange noch keine Verbindung besteht, hat der Server die Aufgabe,
auf einem bestimmten Port zu hören, ob sich dort ein Client mit ihm verbinden
will. Das folgend Aktivitäts-Diagramm veranschaulicht die Situation.

Einige wichtige Server-Methoden
| Signatur
/ Aufruf |
Parameter |
Erklärung |
Exceptions |
Package
/ Klasse |
ServerSocket(int port)
|
Port, auf dem auf einen Client-Anfrage gewartet werden soll |
es wird ein Server erzeugt, der auf dem übergebenen Port auf Clients
wartet |
IOException |
java.net / ServerSocket |
| Socket accept() |
|
nachdem eine Client-Anfrage eingetroffen ist besteht beim Server die Möglichkeit,
die Verbindung zu akzeptieren |
IOException |
java.net / ServerSocket |
void setSoTimeout(int timeout)
|
Wartezeit in Milli-Sekunden |
gibt eine bestimmte Zeit vor, nach der das Warten auf Client-Anfragen
gestoppt wird |
SocketException |
java.net / ServerSocket |
| close() |
|
das Warten auf Client-Anfragen wird beendet |
IOException |
java.net / ServerSocket |
Einige wichtige Client-Methoden der Klasse Socket
| Signatur
/ Aufruf |
Parameter |
Erklärung |
Exceptions |
Package
/ Klasse |
| Socket(String host, int port) |
host: der Host auf dem sich der Server befindet
port: Port, auf dem der Server auf eine Verbindung wartet |
Konstruktor:
Erzeugt einen Stream-Socket und verbindet diesen mit dem angegebenen Port
auf dem angegebenen Host |
IOException |
java.net / Socket |
| Socket(InetAddress address, int port) |
host: IP vom Host auf dem sich der Server befindet
port: Port, auf dem der Server auf eine Verbindung wartet |
Konstruktor:
Erzeugt einen Stream-Socket und verbindet diesen mit dem angegebenen Port
auf der angegebenen Adresse. Dieser Konstruktor kann anstelle des vorherigen
aufgerufen werden, wenn man anstelle des Hostnamens nur dessen IP hat. |
IOException |
java.net / Socket |
| void flush() |
|
Damit beim Senden über eine Socket-Verbindung alles gesendet wird
und nichts zwischengepuffert wird, sollte man grundsätzlich nach dem
Senden diese Methode aufrufen. |
IOException |
java.io / OutputStream
java.io / InputStream |
| void close() |
|
zum Schliessen einer Socket-Verbindung |
IOException |
java.net / Socket |
| String getHostName() |
|
liefert den Namen des Hosts |
- |
java.net / Socket |
| InetAddress getLocalHost() |
|
liefert die IP des eigenen Hosts |
UnknownHostException |
java.net / Socket |
| InputStream getInputStream() |
|
liefert einen InputStream, den man braucht, um Daten über eine Socket-Verbindung
empfangen zu können |
IOException |
java.net / Socket |
OutputStream getOutputStream()
|
|
liefert einen OutputStream, den man braucht, um Daten über eine Socket-Verbindung
verschicken zu können |
IOException |
java.net / Socket |
Java-Code eines Servers
Der folgende Java-Code implementiert einen Server, der auf Port "1234"
auf Anfragen von Clients wartet. Der Server hat die Aufgabe, 2 Zahlen
die der Client über die Socket-Verbindung schickt zu addieren und
das Ergebnis zurück zu schicken.
Es müssen grundsätzlich beide im Bild angegebenen Pakete importiert
werden.
Die Main-Methode startet den Server. Dadurch wird als Attribut die neue
Socket-Verbindung "server" angelegt und im Konstruktor in eine
Endlosschleife gegangen, wo vorerst mal in Zeile 10 angehalten und auf
Nachrichten vom Client gewartet wird.

Beschreibung des Codes:
- solange auf Port 1234 nichts zu hören ist wartet der Server auf
Anfragen (10)
- sobald ein Client eine Zahl schickt wird eine Verbindung aufgebaut
(10 - 12)
- zwei gesendete Zahlen werden eingelesen (13, 14)
- die Summe beider Zahlen wird als Antwort über die Verbindung
übermittelt (15)
- alle gepufferten Bytes abschicken (16)
- Eingabe und Ausgabestrom schliessen (17, 18)
- warten auf weitere Client-Anfragen (10)
Java-Code eines Clients
Jetzt wird ein möglicher Client implementiert, der den Dienst des
Servers aus dem Beispiel oben nutzt. Der Client hat die Aufgabe eine Socket-Verbindung
zum Server aufzubauen, diesem die Zahlen 5 und 10 zu übermitteln,
die Antwort des Servers zu empfangen und diese auf der Konsole auszugeben.
Danach soll die Verbindung geschlossen werden und der Client soll beendet
werden (automatisch, weil alles abgearbeitet wurde).
Die Main-Methode startet wieder nur den Client. Es muss natürlich
bedacht werden, dass zuerst der Server gestartet sein muss, bevor ein
Client eine Anfrage an ihn stellen kann. Nachdem der Client alles abgearbeitet
hat und es diesen nicht mehr gibt, wartet der Server wieder auf neue Anfragen,
weil dieser sich ja in einer Endlosschleife befindet
.
Beschreibung des Codes:
- die Verbindung zum Server wird hergestellt (7 - 9)
- zwei Zahlen werden über die Verbindung übermittelt (10,
11)
- der Ausgabepuffer wird geleert (12)
- das Ergebnis wird von der Eingabe gelesen und auf die Konsole geschrieben
(13)
- die Verbindung zum Server wird beendet (14)
- Eingabe und Ausgabestrom schliessen (15, 16)
|