| Netzwerkadressen |
Wir
wollen mit Java Verbindung aufnehmen mit andern Programmen auf andern
Computern. Im ersten Schritt befassen wir uns mit den Adressen der
Computer im Netz:
- Erstellen Sie
ein neues Projekt z.B. mit dem Namen SocketTest und ich würde vorschlagen
vom Typ Basic Java Application - so können Sie die Tests gleich aus
einem Grafikfenster heraus durchführen (ist etwas aufwändiger, aber
nicht viel).
- Die Klassen für
Netzwerkbelange sind im Package java.net, also ergänzen Sie in SocketTextFrame
die Import Statemenst mit
import java.net.*;
- Wir brauchen eine
Taste um die Verbindungsaufnahme auszulösen und ein Label um die
Ausgaben darzustellen. Damit auf beides aus der ganzen Klasse zugegriffen
werden kann, deklarieren Sie beides vor dem Konstruktor:
Label label;
Button taste;
- Die Instanz
der beiden GUI Elemente erstellen wir im Konstruktor:
label
= new Label("Start");
add(label);
taste = new Button("verbinden");
add(taste, BorderLayout.SOUTH);
- Und
auch der Action Listener für die Taste kommt in den Konstruktor:
// Add action listener.
taste.addActionListener
(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
verbindung();
}
}
);
- Sie
sehen, dass ich vorgesehen habe, dass beim Drücken der Taste eine
Methode verbindung() ausgeführt wird. Also deklarieren wir diese
Methode (nach dem Ende des Konstruktors!):
// Verbindung:
void verbindung() {
try {
String s = "Adresse von Localhost: ";
InetAddress address = InetAddress.getLocalHost();
s = s + address.getHostName();
s = s + " = " + address.getHostAddress();
label.setText(s);
} catch (UnknownHostException e) {
label.setText("Hostadresse unbekannt");
}
}
Hier sind nun die Dinge, welche auf das Netzwerk zugreifen. Dazu einige
Erklärungen:
- Auffällig
ist aber zuerst das Wort try: Immer dann, wenn bei der Ausführung
von Anweisungen ein Fehler (heisst in Java Exception) auftreten
könnte, brauchen wir einen try - catch Block: In der geschweiften Klammer hinter
try stehen die Anweisungen, bei denen was schief gehen könnte, hinter catch
steht in der runden Klammer was schief gehen könnte, also die Exception und
in der
geschweiften Klammer dahinter, was zu tun ist, wenn etwas schief geht.
- Wir machen einen String namnes s, in welchem wir den Text speichern, welcher
im Label erscheinen soll.
- Wir machen eine
Instanz einer Internet - Adresse (Klasse InetAddress) namens address.
Wir machen Sie nicht mit new, sondern mit der Methode getLocalHost
von InetAddress, welche die Adresse des Computers liefert, auf welchem
unser Programm läuft.
- Sie wissen, jeder
Computer, der an einem Netz hängt, hat eine numerische Adresse (IP
Adresse). Diese liefert uns die Methode getHostAddress().
- Viele Computer
haben auch einen Namen. Diesen liefert die Methode getHostName().
- Name und Adresse
werden an den String s gehängt und dann mit label.setText() im Label
dargestellt.
- Testen Sie das
Programm. Sie sollten nach dem Drücken der Taste im Label Name und
IP Adresse Ihres Computers sehen.
|
|
| |
Soviel
zu den Adressen. Jetzt wollen wir eine Verbindung herstellen. So wie
im Computer der Mikroprozessor in einen Sockel gesteckt wird, damit er
mit dem Rest des Computers kommunizieren kann (Bild rechts), so "stecken"
wir auch unser Programm in einen Sockel (Socket), damit
es mit dem Netz kommunizieren kann - und zwar mit irgend einem andern
Socket:
- Wir erzeugen eine
Instanz der Klasse Socket:
void verbindung() {
try {
String h = "www.dgb.ch";
String s = "Verbinden zu " + h;
InetAddress address = InetAddress.getByName(h);
Socket sock = new Socket(address,80);
label.setText(s);
} catch (UnknownHostException e) {
label.setText("Hostadresse unbekannt");
} catch (IOException e) {
label.setText("IO Exception!");
}
}
Auch hier wieder einige Erklärungen:
- Über die Socket
Verbindung werden Daten transferiert, ganz ähnlich wie wenn Java
in eine Datei schreibt
oder
von einer
solchen
liest.
Dabei kann es eine IOException geben (IO steht für Input - Output),
deshalb muss diese Exception gecatcht werden. Aber Achtung alles
zu IO ist im Package java.io, also auch dieses
impoertieren!
- Im Konstruktor
von sock steht als Parameter neben der Adresse die Zahl 80. Sie gibt
den Port an, durch welchen wir die Verbindung zum
Gerät herstellen. Gemäss Standard antworten Webserver über den Port
80.
- Testen Sie! Es
kann sein, dass Sie zu www.dgb.ch nicht verbinden können, wegen unserem
Firewall. Dann verbinden Sie zu 10.1.1.253, auch hier wird ein Webserver
betrieben.
Jetzt sollen Daten
zu und vom Server geschickt werden. Dies geschieht durch einen
Stream: Über einen InputStream holt eine Java Applikation Daten, über
einen
OutputStream schickt sie Daten. Einen OutputStream können wir an
einen PrintStream weiterleiten, welcher Dinge wie Zeilenvorschübe
etc. produzieren kann. Ebenso kann ein DataInputstream ganze Zeilen
lesen. So können übrigens ganze Ketten von Streams gebildet werden.
Im Folgenden schicken wir mit println() dem Webserver den HTTP Befehl
GET, welcher ihn anweist, eine Webseite zurückzuschicken. Das ist der
häufigste
Befehl, den auch ein Browser dem Webserver schickt. Anschliessend lesen
wir das, was der Webserver schickt mit readLine(). Im Folgenden wird
die erste Zeile der Hauptseite des Webservers 10.1.1.253 im lokalen
Netz gelesen. Diese Seite heisst default.htm. Oft heissen Hauptseiten
auch index.htm oder index.html.
- Ergänzen Sie folgendermassen
und testen Sie:
DataInputStream in = new DataInputStream(sock.getInputStream());
PrintStream out = new PrintStream(sock.getOutputStream());
out.println("GET /default.htm");
s = in.readLine();
label.setText(s);
- Schaffen
Sie es mehrere Zeilen zu lesen und darzustellen? Dazu sollten Sie
das Label in eine TextArea abändern, denn das Label ist nur einzeilig.
Eine neue Zeile erhalten Sie, indem Sie die Zeilenfolge "\n" schicken.
Jetzt soll eine
Java Applikation mit einer andern kommunizieren. Dazu muss die
eine ein Server sein (wie ein Webserver) und die andere ein Client
(wie
bisher). Zum Test lassen Sie beides, Client und Server, auf dem
selben PC laufen. Später können Sie dann die beiden auf verschiedenen Maschinen
laufen lassen.
- Erzeugen Sie wieder
ein neues Projekt, z.B. namens ServerTest vom Typ Empty Java Project.
Erstellen Sie die neue Datei ServerTest.java und fügen Sie sie dem
Projekt zu.
- Die neue Quelldatei
sieht folgendermassen aus:
import java.net.*;
import java.io.*;
public class ServerTest {
public static void main(String args[]) throws IOException {
System.out.println("Server
started ...");
ServerSocket servSock = new ServerSocket(80);
for (;;) {
Socket clntSock = servSock.accept();
System.out.println("Client accepted!");
clntSock.close();
}
}
}
Dazu wieder Erklärungen:
- Wir importieren
wieder .net und .io wie bisher.
- Um einen try -
catch Block zu vermeiden, können wir auch einfach sagen, dass die
Methode main() ev. eine IOException "werfen" wird (throws).
- Diesmal machen
wir nicht einen normalen, sondern einen ServerSocket, welcher wie
ein Webserver über Port 80 kommuniziert.
- In einer unendlichen
Schlaufe ( for(;;)! ) wartet der ServerSocket auf einen "Anruf" mit
der Methode accept(). Die Methode erzeugt eine Instanz von Seocket,
über welche dann mit dem Client kommuniziert werden kann.
- Hier melden wir
auf der Konsole einfach, dass ein Client akzeptiert wurde und brechen
die Verbindung mit close() wieder ab.
- Übersetzen Sie
und führen Sie dann das Programm nicht aus der IDE, sondern aus einem
DOS Fenster aus ("Start", "Programme", "MS DOS Eingabeaufforderung",
ServerTest.class suchen und ausführen mit java ServerTest).
- Lassen Sie das
DOS Fenster offen, gehen Sie zurück in die IDE, machen Sie das Projekt
SocketTest aktiv, stellen Sie die Verbindung zu Ihrem Gerät her (10.1.1.x),
übersetzen Sie und führen Sie aus. Das Programm wird wohl hängen
bleiben, weil es vom Server keine Antwort kriegt. Mit der Tastenkombination
<Ctrl>+<c> können Sie das Programm abbrechen.
- Schauen Sie im
DOS Fenster des Servers nach, ob er ihren Anruf akzeptiert hat. Stoppen
Sie den Server mit <Ctrl>+<c>.
- Eventuell testen
Sie jetzt ob die Kommunikation auch von einem Gerät zum ander funktioniert.
Vielleicht ist es sowieso einfacher, wenn Sie auf einem Gerät den
Client und auf dem andern den Server betreiben, dann müssen Sie nicht
immer das aktive Projekt wechseln.
- Sie sollten den
Server jetzt noch etwas intelligenter machen. Wir brauchen wieder
Input- und OutputStream und machen in diesem Falle einfach nur ein
Echo für genau eine Zeile:
public static void main(String args[]) throws IOException {
System.out.println("Server started ...");
ServerSocket servSock = new ServerSocket(80);
for (;;) {
Socket clntSock = servSock.accept();
System.out.println("Client accepted!");
DataInputStream in = new DataInputStream(clntSock.getInputStream());
PrintStream out = new PrintStream(clntSock.getOutputStream());
String s = in.readLine();
out.println(s);
clntSock.close();
}
}
- Übersetzen und
starten Sie den Server wieder. Ändern Sie den Client so, dass er
eine Zeile schickt und eine liest.
Jetzt ist der Kommunikation
zwischen zwei Computern keine Grenze gesetzt! Es könnten ja auf beiden
Server laufen. Das Gerät, welches als erstes die Verbindung aufbaut
wird dann zum Client. Es müsste dann wohl an beiden Orten je ein Fenster
für den Dialog und eines für die Eingabe geben - und fertig ist das
Chatprogramm... Fast, denn ein richtiges Chatprogramm sieht in regelmässigen
Abständen nach ob was von der Gegenseite kommt. Ein Ablauf in regelmässigen
Abständen wird in Java mit einem Thread realisiert. Siehe dazu im Kapitel Threads.
|
 |