Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 16 Netzwerkprogrammierung
gp 16.1 Grundlegende Begriffe
gp 16.1.1 Internet-Standards und RFC
gp 16.2 URL-Verbindungen und URL-Objekte
gp 16.2.1 Die Klasse URL
gp 16.2.2 Informationen über eine URL
gp 16.2.3 Der Zugriff auf die Daten über die Klasse URL
gp 16.2.4 Verbindungen durch einen Proxy-Server
gp 16.3 Die Klasse URLConnection
gp 16.3.1 Methoden und Anwendung von URLConnection
gp 16.3.2 Protokoll- und Content-Handler
gp 16.3.3 Im Detail: vom URL zu URLConnection
gp 16.3.4 Autorisierte URL-Verbindungen mit Basic Authentication
gp 16.3.5 Apache Jakarta HttpClient
gp 16.4 Das Common Gateway Interface
gp 16.4.1 Parameter für ein CGI-Programm
gp 16.4.2 Kodieren der Parameter für CGI-Programme
gp 16.4.3 Eine Suchmaschine ansprechen
gp 16.5 Host- und IP-Adressen
gp 16.5.1 Das Netz ist Klasse ...
gp 16.5.2 IP-Adresse des lokalen Hosts
gp 16.5.3 Die Methode getAllByName()
gp 16.6 NetworkInterface
gp 16.7 IPv6 für Java mit Jipsy
gp 16.8 Socket-Programmierung
gp 16.8.1 Das Netzwerk ist der Computer
gp 16.8.2 Standarddienste unter Windows nachinstallieren
gp 16.8.3 Stream-Sockets
gp 16.8.4 Informationen über den Socket
gp 16.8.5 Mit telnet an den Ports horchen
gp 16.8.6 Ein kleines Echo - lebt der Rechner noch?
gp 16.9 Client/Server-Kommunikation
gp 16.9.1 Warten auf Verbindungen
gp 16.9.2 Ein Multiplikations-Server
gp 16.10 SLL-Verbindungen mit JSSE
gp 16.11 Web-Protokolle mit NetComponents nutzen
gp 16.12 E-Mail
gp 16.12.1 Wie eine E-Mail um die Welt geht
gp 16.12.2 Übertragungsprotokolle
gp 16.12.3 Das Simple Mail Transfer Protocol
gp 16.12.4 E-Mails versenden mit Suns JavaMail-API
gp 16.12.5 MimeMultipart-Nachrichten schicken
gp 16.12.6 E-Mails mittels POP3 abrufen
gp 16.13 Arbeitsweise eines Web-Servers
gp 16.13.1 Das Hypertext Transfer Protocol (HTTP)
gp 16.13.2 Anfragen an den Server
gp 16.13.3 Die Antworten vom Server
gp 16.14 Datagram-Sockets
gp 16.14.1 Die Klasse DatagramSocket
gp 16.14.2 Datagramme und die Klasse DatagramPacket
gp 16.14.3 Auf ein hereinkommendes Paket warten
gp 16.14.4 Ein Paket zum Senden vorbereiten
gp 16.14.5 Methoden der Klasse DatagramPacket
gp 16.14.6 Das Paket senden
gp 16.14.7 Die Zeitdienste und ein eigener Server und Client
gp 16.15 Internet Control Message Protocol (ICMP)
gp 16.15.1 Ping
gp 16.16 Multicast-Kommunikation


Galileo Computing

16.8 Socket-Programmierungdowntop

Die URL-Verbindungen sind schon High-level-Verbindungen, wir müssen uns nicht erst um Übertragungsprotokolle wie HTTP oder - noch tiefer - TCP/IP kümmern. Aber alle höheren Verbindungen bauen auf Sockets auf, und auch die Verbindung zu einem Rechner über URL ist mit Sockets realisiert. Beschäftigen wir uns also nun etwas mit dem Hintergrund.


Galileo Computing

16.8.1 Das Netzwerk ist der Computerdowntop

Die Rechner, die im Internet verbunden sind, kommunizieren über Protokolle, wobei TCP/IP das wichtigste geworden ist. Die Entwicklung des Protokolls geht in die Achtzigerjahre zurück. Die ARPA (Advanced Research Projects Agency) gab der Universität von Berkeley (Kalifornien) den Auftrag, unter Unix das TCP/IP-Protokoll zu implementieren, um dort in dem Netzwerk zu kommunizieren.1 Was sich die Kalifornier ausgedacht hatten, fand auch in der Berkeley Software Distribution (BSD), einer Unix-Variante, Verwendung: die Berkeley-Sockets. Mittlerweile hat sich das Berkeley-Socket-Interface über alle Betriebssystemgrenzen hinweg entwickelt und ist der De-facto-Standard für TCP/IP-Kommunikation. Es finden sich in allen möglichen Unix-Derivaten und auch unter Windows Socket-Implementierungen. So ist Windows Socket ein Interface für Microsoft Windows, mit dem sich die Sockets auch unter dieser Plattform nutzen lassen. Die Spezifikation von Windows Socket basiert auf BSD Unix Version 4.3.

Ein Socket dient zur Abstraktion und ist ein Verbindungspunkt in einem TCP/IP-Netzwerk. Werden mehrere Computer verbunden, so implementiert jeder Rechner einen Socket: Derjenige, der Daten empfängt (Client), öffnet eine Socket-Verbindung zum Horchen, und derjenige, der sendet, öffnet eine Verbindung zum Senden (Server). Es lässt sich in der Realität nicht immer ganz trennen, wer Client und wer Server ist, da Server ebenfalls zum Datenaustausch Verbindungen aufbauen können. Doch für den Betrachter von außen ist der Server der Wartende und der Client derjenige, der die Verbindung initiiert.

Damit der Empfänger den Sender auch hören kann, muss dieser durch eine eindeutige Adresse als Server ausgemacht werden. Er bekommt also eine IP-Adresse im Netz und eine ebenso eindeutige Port-Adresse. Der Port ist so etwas wie eine Zimmernummer im Hotel. Die Adresse bleibt dieselbe, aber in jedem Zimmer sitzt einer und macht seine Aufgaben.

Für jeden Dienst (Service), den ein Server zur Verfügung stellt, gibt es einen Port. Diese Adressen sind aber nicht willkürlich vergeben, sondern werden von der IANA2 (Internet Assigned Numbers Authority) vergeben. Die IANA ging aus der ISOC (Internet Society) und der FNC (Federal Network Council) hervor. Die Internet Authority ist der zentrale Koordinator für die IP-Adressen, Domain-Namen, MIME-Typen und für viele andere Parameter, unter anderem auch für die Port-Nummern - Näheres unter http://www.iana.org/.

Eine Port-Nummer ist eine 16-Bit-Zahl und in die Gruppen »System« und »Benutzer« eingeteilt. Die so genannten Well-Known-System-Port- (auch Contact Port-) Nummern liegen im Bereich von 0-1023. (Noch vor einigen Jahren haben 255 definierte Nummern ausgereicht.) Die User-Ports umfassen den restlichen Bereich von 1024-65535. Die folgende Tabelle zeigt einige wenige dieser Port-Nummern. Die vollständige Liste ist unter http://www.iana.org/assignments/port-numbers verfügbar.


Service Port Beschreibung
echo 7 Echo
daytime 13 Daytime
qotd 17 Quote of the Day
ftp-data 20 File Transfer [Default Data]
ftp 21 File Transfer [Control]
ssh 22 SSH Remote Login Protocol
telnet 23 Telnet
smtp 25 Simple Mail Transfer
time 37 Time
nicname 43 Who Is
domain 53 Domain Name Server
whois++ 63 whois++
gopher 70 Gopher
finger 79 Finger
www 80 World Wide Web HTTP
www-http 80 World Wide Web HTTP
pop2 109 Post Office Protocol - Version 2
pop3 110 Post Office Protocol - Version 3
pwdgen 129 Password Generator Protocol

Tabelle 16.2 Einige ausgewählte System-Ports

Die auf einem Unix-System installierten Ports sind meistens unter /etc/services einzusehen.


Galileo Computing

16.8.2 Standarddienste unter Windows nachinstallierendowntop

Wir wollen nun mit der Netzwerkprogrammierung bei den Clients beginnen. Diese greifen auf einen Server zu und nutzen dessen Dienste. Ein solcher Dienst wäre etwa ein Zeit-Server oder ein Echo-Server. Der Zeit-Server liefert die aktuelle Tageszeit, und ein Echo-Server würde alle gesendeten Zeichenketten wieder zurückschicken. Wenn wir allerdings einen Dienst auf einem Rechner nutzen wollen, dann muss dieser auch angeboten werden. Unter Unix gibt es eine ganze Menge von Standarddiensten. Allerdings haben die Leser, die mit Windows arbeiten, überhaupt keine Dienste (ein Portscann zeigt dies leicht). Um Unix- und Windows-Leser auf den gleichen Stand zu bringen, wollen wir unter Windows zwei Standarddienste installieren. Diese sind unter Windows abhängig von WinSock (http://www.sockets.com/). WinSock ist die Abkürzung für Windows Socket und wird immer dann benötigt, wenn ein Computer in einem lokalen Netzwerk und über Modem an das Internet soll. Eine manuelle Installation von WinSock ist nicht mehr nötig; TCP/IP sollte aber auf dem Rechner installiert sein. Da sich viele Rechner jedoch im Internet oder im Netz befinden, ist dies vermutlich die Standardkonfiguration. Uns interessieren aber die Dienste. Sie bauen auf WinSock auf, und unter der Web-Seite »WinSock Development Information« finden wir unter »Sample Applications« einen Verweis (ftp://ftp.sockets.com/sockets/wsa_all.zip) auf das Paket mit den Quellcodes. Dieses Paket ist etwas über ein Megabyte groß und enthält mehr als wir benötigen.3 Daher habe ich nur die die ausführbaren Programme unter http://java-tutor.com/download/internet/WindowsSocketsBinaries.zip abgelegt. Das Archiv hat eine Größe von 196 KB.


Galileo Computing

16.8.3 Stream-Socketsdowntop

Ein Stream-Socket baut eine feste Verbindung zu einem Rechner auf. Das Besondere dabei ist: Die Verbindung bleibt für die Dauer der Übertragung bestehen. Dies ist bei der anderen Form der Sockets, den Datagram-Sockets, nicht der Fall. Wir behandeln die Stream-Sockets zuerst.

Eine Verbindung zum Server aufbauen

Um Daten von einer Stelle zur anderen zu schicken, muss zunächst eine Verbindung zum Server bestehen. Dieser wiederum beantwortet die eingehenden Fragen. Mit den Netzwerkklassen unter Java lassen sich sowohl Client- als auch Server-basierte Programme schreiben. Da die Client- noch einfacher als die Server-Seite ist - in Java ist Netzwerkprogrammierung ein Genuss - beginnen wir mit dem Client. Dieser muss zu einem horchenden Server verbunden werden. Diese Verbindung wird durch die Socket-Klasse aufgebaut:

Socket clientSocket = new Socket( "die.weite.welt", 80 );

Der erste Parameter des Konstruktors ist der Name des Servers (Host-Adresse), mit dem wir uns verbinden wollen. Der zweite Parameter ist der Port, wir haben hier 80 gewählt, um zu einem Web-Server Verbindung aufzubauen.


Hinweis Verbinden wir ein Applet mit dem Server, von dem es geladen wurde, würden wir mit getCodeBase().getHost() arbeiten.
Socket server = new Socket( getCodeBase().getHost(), 7 );

Es gibt noch eine andere Möglichkeit, zu einem Host zu gelangen: über die Klasse InetAddress.

secondSocket = new Socket( server.getInetAddress(), 1234 );

Alternativ ermittelt die Funktion getHostByName(String) die InetAddress eines Hosts. Ist der Server nicht erreichbar, so wirft das System bei allen Socket-Konstruktionsversuchen eine UnknownHostException aus.


class java.net.Socket

gp Socket() throws IOException
Erzeugt einen nicht verbundenen Socket. Es ist der Standard SocketImpl.
gp Socket( SocketImpl impl ) throws IOException
Erzeugt einen unverbundenen Socket mit einer benutzerdefinierten SocketImpl.
gp Socket( String host, int port ) throws IOException
Erzeugt einen Stream-Socket und verbindet ihn mit der Port-Nummer am angegebenen Host.
gp Socket( InetAddress address, int port ) throws IOException
Erzeugt einen Stream-Socket und verbindet ihn mit der Port-Nummer am Host mit der angegebenen IP-Nummer.
gp Socket( String host, int port, InetAddress localAddr, int localPort )
throws IOException
Erzeugt einen Socket und verbindet ihn zum Host am Port.
gp Socket( InetAddress address, int port,.InetAddress localAddr, int localPort )
throws IOException
Erzeugt einen Socket und verbindet ihn zum Host am Port.

Die Verbindung wieder abbauen

Die Methode close() leitet das Ende einer Verbindung ein und gibt dem Betriebssystem die reservierten Handles zurück. Ohne Freigabe könnte das Betriebssystem unter Umständen nach einer gewisssen Zeit keine Handles mehr zurückgeben, und weiteres Arbeiten wäre nicht möglich. Dies geht so weit, dass auch der Browser keine HTML-Seite mehr vom Server bekommt. Taucht also das Verhalten auf, dass einige Verbindungen aufgebaut werden können, danach aber Schluss ist, sollte diese Lücke untersucht werden.


class java.net.Socket

gp void close() throws IOException
Schließt den Socket.

Server unter Spannung: die Ströme

Besteht erst einmal die Verbindung, so wird mit den Daten vom Server genauso verfahren wie mit den Daten aus einer Datei. Die Socket-Klasse liefert uns Streams, mit denen wir lesen und schreiben können. Nun bietet die Klasse Socket die Methoden getInputStream() und getOutputStream(), die einen Zugang zum Datenstrom erlauben. Holen wir uns zunächst einen Ausgabestrom vom Typ OutputSteam:

OutputStream out = server.getOutputStream()

Oft wird dieser dann noch schnell zu einem DataOutputStream oder PrintStream beziehungsweise PrintWrtier gemacht, damit die Ausgabemöglichkeiten vielfältiger sind. Genauso wird mit dem Eingabestrom verfahren. Wandeln wir ihn gleich in einen BufferedReader um:

BufferedReader in = new BufferedReader(
  new InputStreamReader( server.getInputStream()) );

Wir kennen das Prinzip schon von den URL-Verbindungen.


class java.net.Socket

gp InputStream getInputStream() throws IOException
Liefert den Eingabestrom für den Socket.
gp OutputStream getOutputStream() throws IOException
Liefert den Ausgabestrom für den Socket.

Galileo Computing

16.8.4 Informationen über den Socketdowntop

Wie beim URL-Objekt, so lassen sich auch beim Socket keine grundsätzlich wichtigen Parameter nachträglich ändern. Port-Adresse wie auch das Ziel müssen beim Erzeugen bekannt sein. Aber, wie bei einer URL auch, es lassen sich Informationen über das Socket-Objekt einholen.


class java.net.Socket

gp InetAddress getInetAddress()
Liefert die Adresse, mit der der Socket verbunden ist.
gp InetAddress getLocalAddress()
Liefert die lokale Adresse, an die der Socket gebunden ist.
gp int getPort()
Gibt den Remote-Port zurück, mit dem der Socket verbunden ist.
gp int getLocalPort()
Gibt den lokalen Port des Sockets zurück.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

16.8.5 Mit telnet an den Ports horchendowntop

Wir können zum Server mittels des Kommandozeilenprogramms telnet eine Verbindung aufbauen und die Funktionalität eines Servers einfach prüfen, wenn dieser auf ASCII-Kommandos antwortet. Die Signatur von telnet ist:

$ telnet IP Port

Mit dieser Technik können wir uns zum Beispiel direkt mit dem FTP-Server verbinden, ohne ein Frontend wie ftp zu nutzen, oder auch ein Echo-Kommando absetzen, um damit den Server auf Erreichbarkeit zu testen.


Galileo Computing

16.8.6 Ein kleines Echo - lebt der Rechner noch?toptop

Abbildung
Hier klicken, um das Bild zu Vergrößern

Möchten wir überprüfen, ob ein Rechner in der Lage ist, Kommandos über seine Netzwerkschnittstelle entgegenzunehmen, so können wir ein Kommando hinschicken und warten, ob etwas passiert. Am einfachsten ist der Aufbau zu dem Echo-Server, ein Service, der alle ankommenden Kommandos gleich wieder zurückschickt.

Wenn wir den Echo-Dienst nutzen wollen, dann senden wir ein Testwort zum Server und überprüfen, ob das gleiche Wort wieder zurückkommt. Die Herstellung der Verbindung zum Echo-Server ist mit der Socket-Klasse kein Problem. Da der Echo-Service immer an Port 7 liegt, eröffnet die Anweisung Socket(IPAdress, 7) die Verbindung. Anschließend lassen sich InputStream und OutputStream holen, und die Anfrage lässt sich verarbeiten. Die IP-Adresse lesen wir aus der Kommandozeile.


Hinweis Ein solcher Echo-Server ist oft unter Unix aktiv, unter Windows und anderen Systemen jedoch nicht. Wir können daher nur zu einem Rechner die Verbindung aufbauen und unser Programm prüfen, wenn dieser Dienst auch tatsächlich läuft. Wenn wir lokal auf einem Windows-Rechner arbeiten, dann können wir uns einige primitive Dienste durch Hilfsprogramme installieren. Die Quelle wurde oben schon genannt und ist http://java-tutor.com/download/internet/WindowsSocketsBinaries.zip. Läuft der Echo-Dienst unter einem Rechner nicht, dann wird eine »java.net.ConnectException: Connection refused: no further information«-Ausnahme angezeigt.

Listing 16.12 Echo.java

import java.io.*;
import java.net.*;
class Echo
{
  public static void main( String args[] ) throws Exception
  {
    Socket t = new Socket( args[0], 7 );
    BufferedReader in = new BufferedReader(
      new InputStreamReader( t.getInputStream()) );
    PrintStream os = new PrintStream( t.getOutputStream() );
    String test = "Superkalifragilistischexpialigetisch";
    os.println( test );
    String s = in.readLine();
    if ( s.equals(test) )
      System.out.println( "Hurra, er lebt!" ) ;
    t.close();
  }
}





1 Die Geschichte, dass das Internet nur deshalb entwickelt wurde, damit bei Rechnerausfällen durch kriegerische Aktivitäten weiter Kommunikation möglich ist, ist so falsch. Larry Roberts sagt dazu, dass die Entwickler dem Ministerium die Vorteile des Internets nur deswegen so verkauften, damit sie mehr Forschungsgelder bekamen.

2 Nicht zu verwechseln mit »Illinois Association of Nurse Anesthetists« beziehungsweise »Intermodal Association of North America«!

3 Die einzelnen Programme liegen allerdings auch unter>http://www.sockets.com/sample.htm.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de