Tutorial: Netzwerk-Funktion der Engine
Achtung!!!
Dieses Tutorial baut auf einigen Grundprinzipien der Kommunikation zwischen Computern auf. Verwendet werden:
- Server-Client-Modell
- Schicht 3 & 4 Kommunikation: IP & Port
Inhaltsverzeichnis
Ziel des Tutorials
Nach diesem Tutorial kannst du die Netzwerkfunktionen der Engine benutzen:
- Server und Clients für Computer-zu-Computer-Kommunikation aufbauen.
- Informationen zwischen Computern austauschen.
Grundprinzip: Server und Client
Netzwerkverbindungen zwischen Computern werden im Allgemeinen als Server-Client-Verbindungen bezeichnet. Das Grundprinzip funktioniert so:
- Ein Server bietet seine Dienste beliebig vielen Clients an.
- Ein Client kann einen Server kontaktieren, um seine Dienste in Anspruch zu nehmen.
Entsprechend gibt es in der Engine Alpha die Klassen Server
und Client
. Server und Client können beide sowohl Nachrichten empfangen als auch verschicken.
Einen Server erstellen
Ein Server kann einfach mit dem Konstruktor aufgebaut werden:
public Server(int port)
Der Port ist eine Kennzahl, mit der verschiedene Internetdienste sich unterscheiden können, z.B. hat HTTP Port 80. Du kannst für deinen Server einen beliebigen Port wählen, allerdings sollte deine Portnummer größer als 1024 sein, da bis dahin die Nummern für bekannte Dienste reserviert sind (sog. Well Known Ports).
Damit ist der Server auch schon erstellt und bereit, Clients zu empfangen.
Einen Client erstellen
Wenn ein Server wartet, macht es Sinn, den Client zu startet. Der Client kann mit diesem Konstruktor aufgebaut werden:
public Client(String ipAdresse, int port)
Der Parameter ipAdresse
beschreibt die IP-Adresse des Servers, mit dem sich der Client verbinden soll. Sie wird als String übergeben, z.B. "198.162.0.2", oder "123.56.23.1".
Der Port funktioniert wie bereits in der Server-Sektion beschrieben. Damit sich der Client auch wirklich mit dem Server verbindet, müssen die Portnummern bei Server und Client übereinstimmen.
Nachrichten verschicken und empfangen
Die grundlegenden Methoden
Hat sich ein Client mit dem Server verbunden, können beide Seiten Nachrichten austauschen. Hierfür haben beide Klassen dieselben Methoden:
Sende-Methode | Funktion (Sende-Methode) | -> | Zugehörige Empfange-Methode | Funktion (Empfange-Methode) |
---|---|---|---|---|
public void sendeString (String string) |
Sendet den übergebenen Wert des entsprechenden Datentyps an den Kommunikationspartner. | empfangeString (String string) |
Wird automatisch aufgerufen, wenn der Kommunikationspartner, einen Wert des entsprechenden Datentyps sendet. Der Wert wird im Parameter übergeben. | |
public void sendeInt (int i) |
empfangeInt (int i) | |||
public void sendeByte (byte b) |
empfangeByte (byte b) | |||
public void sendeDouble (double d) |
empfangeDouble (double d) | |||
public void sendeChar (char c) |
empfangeChar (char c) | |||
public void sendeBoolean (boolean b) |
empfangeBoolean (boolean b) |
Senden & Empfangen: Client
Senden und Empfangen als Client funktioniert, indem man eine eigene Klasse (z.B. MeinClient
) von Client
ableitet. Alle Sende&Empfange-Methoden sind bereits im Client enthalten. Die Sende-Methoden kann man also direkt ausführen (da sie von Client vererbt werden), die Empfange-Methoden, auf die man reagieren will, kann man einfach überschreiben. Konkret sieht dein eigener Client funktioniert dein Client also zum Beispiel so:
import ea.*;
public class MyClient
extends Client {
//...
public MyClient(String ipAdresse) {
//Super-Konstruktor aufrufen. Portnummer ist identisch mit der des Servers.
super(ipAdresse, 123456);
//weiteres ...
}
//Ich will auf String-Sendungen reagieren. Deshalb überschreibe ich die
//entsprechende Empfange-Methode!
@Override
public void empfangeString(String string) {
if(string.equals("versionsnummer-angeben")) {
//Ich kann die sende-Methode einfach aufrufen
sendeInt(3);
}
}
//...
}
Senden & Empfangen: Server
Senden und empfangen ist beim Server komplizierter. Ein Client hat immernur eine Verbindung zu einem Server, daher ist klar, wohin er Daten sendet und woher er sie empfängt. Ein Server hingegen kann mehrere Verbindungen zu mehreren Clients gleichzeitig haben. Daher muss man sich bei jeder zu sendenden Nachricht fragen "Wohin damit?" und bei jeder empfangenen Nachricht "Woher kommt die?".
Hierzu gibt es zwei Möglichkeiten in der Engine:
- Broadcast-Methode: Jede zu sendende Nachricht wird an jeden Client geschickt. Bei empfangenen Nachrichten wird nicht unterschieden, von welchem Client sie kommen.
- Dedizierte Methode: Jede Verbindung zu jedem Client, die der Server hat, wird einzeln behandelt. Sie hat jeweils eigene Sende/Empfange-Methoden nur für diesen einen Client.
Broadcast-Methode
Diese Methode ist die einfachere. Senden funktioniert hierbei genau wie beim Client
. Die Klasse Server
hat ebenfalls alle Senden-Methoden. Ein solcher Aufruf sorgt dafür, dass die zu übermittelnde Nachricht direkt an alle Clients übermittelt wird.
Empfangen ist ein klein wenig umständlicher. Hierfür musst du das Interface Empfaenger
implementieren, welches einfach nur alle Senden-Methoden beinhaltet. Dieses kannst du anschließend als globalen Empfänger beim Server anmelden. Dann wird für jede Nachricht, die der Server empfängt - ganz egal von welchem Client - die entsprechende Empfangen-Methode ausgeführt. Konkret kann das zum Beispiel so aussehen:
public class MeineServerApp {
}