6. Netzwerkprogrammierung (LK)
Der nachfolgende Abschnitt gliedert sich nach den drei Klassen der Netzwerkbibliothek (Connection, Client und Server), die im LK die Grundlage von Client-Server-Projekten darstellt.
Die Klasse Connection
Objekte der Klasse Connection ermöglichen eine Netzwerkverbindung zu einem Server mittels TCP/IP-Protokoll. Nach Verbindungsaufbau können Zeichenketten (Strings) zum Server gesendet und von diesem empfangen werden.
TimeClient
Im folgenden Beispiel wird Kontakt zu einem öffentlichen Time-Server aufgenommen und ohne das Versenden einer eigenen Nachricht eine Nachricht des Servers (die aktuelle Zeit) abgewartet.
import netz.*;
public class TimeClient {
public String getTime() {
Connection con = new Connection("time.fu-berlin.de",13);
return con.receive();
}
}
EchoClient
Im Gegensatz zum vorherigen Beispiel wird zunächst eine eigene Nachricht zum (Echo-)Server geschickt, bevor erneut auf Antwort des Servers gewartet wird.
import netz.*;
public class EchoClient1 {
Connection con;
public void starteClient(String pIPAdresse, int pPort) {
con = new Connection(pIPAdresse, pPort);
}
public String sendeNachricht(String pNachricht) {
con.send(pNachricht);
return con.receive();
}
public void beendeVerbindung() {
con.close();
}
}
Die Klasse Client
Objekte von Unterklassen der abstrakten Klasse Client ermöglichen Netzwerkverbindungen zu einem Server mittels TCP/IP-Protokoll. Nach Verbindungsaufbau können Zeichenketten (Strings) zum Server gesendet und von diesem empfangen werden, wobei der Nachrichtenempfang nebenläufig geschieht. Jede empfangene Nachricht wird einer Ereignisbehandlungsmethode übergeben, die in Unterklassen implementiert werden muss (vgl. Methode processMessage).
EchoClient
Das folgende Beispiel zeigt eine Umsetzung des Echo-Clients als Unterklasse der Klasse Client. Zu beachten ist hier das Überlagern der Methode processMessage.
import netz.*;
public class EchoClient2 extends Client {
public EchoClient2(String pIPAdresse, int pPortNr) {
super(pIPAdresse, pPortNr);
}
public void processMessage(String pMessage) {
System.out.println(pMessage);
}
public void sendeNachricht(String pNachricht) {
this.send(pNachricht);
}
}
Die Klasse Server
Objekte von Unterklassen der abstrakten Klasse Server ermöglichen das Anbieten von Serverdiensten, so dass Clients Verbindungen zum Server mittels TCP/IP-Protokoll aufbauen können. Verbindungsannahme, Nachrichtenempfang und Verbindungsende geschehen nebenläufig. Auf diese Ereignisse muss durch Überschreiben der entsprechenden Ereignisbehandlungsmethoden reagiert werden (vgl. Methoden processNewConnection, processMessage und processClosingConnection).
EchoServer
Das fgolgende Beispiel zeigt eine Umsetzung eines Echo-Servers als Unterklasse der Klasse Server. Zu beachten ist hier das Überlagern der drei genannten Methoden.
import netz.*;
public class EchoServer extends Server {
public EchoServer (int pPortNum) {
super(pPortNum);
}
public void processNewConnection(String pClientIP, int pClientPort) {
System.out.println("! Neue Verbindung " + pClientIP + ":" + pClientPort);
}
public void processMessage(String pClientIP, int pClientPort, String pMessage) {
System.out.println(">>" + pClientIP + ":" + pClientPort + " : " + pMessage);
this.send(pClientIP, pClientPort, pMessage);
}
public void processClosingConnection(String pClientIP, int pClientPort) {
System.out.println("! Abmeldung Client " + pClientIP + ":" + pClientPort);
}
}
RateServer
Das abschließende Beispiel setzt einen einfachen Zahlenraten-Server als Client-Server-Lösung mit beliebig vielen Mitspielern um.
import netz.*;
import java.util.*;
public class RateServer extends Server {
private Random zufall;
private int ratezahl;
public RateServer(int pPortNr) {
super(pPortNr);
zufall = new Random();
ratezahl = zufall.nextInt(1000)+1;
System.out.println("Der Server ist gestartet. PortNr: "+pPortNr);
}
public void processClosingConnection(String pClientIP, int pClientPort) {
System.out.println(""+pClientIP+" "+pClientPort+" hat sich abgemeldet.");
}
public void processMessage(String pClientIP, int pClientPort, String pNachricht) {
try {
int zahl = Integer.parseInt(pNachricht);
if (zahl == ratezahl) {
send(pClientIP, pClientPort,pClientIP+" "+pClientPort+"+ok Herzlichen Glückwunsch");
System.out.println("Gewinner: " + pClientIP + ":" + pClientPort);
ratezahl = zufall.nextInt(1000)+1;
sendToAll("Neues Spiel");
System.out.println("Neues Spiel gestartet");
} else {
if (zahl < ratezahl) {
send(pClientIP, pClientPort,"+ok "+zahl+" ist zu klein");
} else {
send(pClientIP, pClientPort,"+ok "+zahl+" ist zu gross");
}
}
} catch (Exception e) {
send(pClientIP, pClientPort, "-err Bitte Zahl zwischen 1 und 1000 schicken");
}
System.out.println(""+pClientIP+" "+pClientPort+" "+pNachricht);
}
public void processNewConnection(String pClientIP, int pClientPort) {
send(pClientIP, pClientPort, "+ok Willkommen. "+pClientIP+" "+pClientPort);
send(pClientIP, pClientPort, "Bitte Zahl schicken");
}
}