Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 18 Netzwerkprogrammierung
Pfeil 18.1 Grundlegende Begriffe
Pfeil 18.1.1 Internet-Standards und RFC
Pfeil 18.2 URI und URL
Pfeil 18.2.1 URI
Pfeil 18.2.2 Die Klasse URL
Pfeil 18.2.3 Informationen über eine URL
Pfeil 18.2.4 Der Zugriff auf die Daten über die Klasse URL
Pfeil 18.2.5 Verbindungen durch einen Proxy-Server
Pfeil 18.3 Die Klasse URLConnection
Pfeil 18.3.1 Methoden und Anwendung von URLConnection
Pfeil 18.3.2 Protokoll- und Content-Handler
Pfeil 18.3.3 Im Detail: vom URL zur URLConnection
Pfeil 18.3.4 Der Protokoll-Handler für Jar-Dateien
Pfeil 18.3.5 Basic Authentication/Proxy-Authentifizierung
Pfeil 18.4 Mit GET und POST Daten übergeben
Pfeil 18.4.1 Kodieren der Parameter für Serverprogramme
Pfeil 18.4.2 Eine Suchmaschine ansprechen
Pfeil 18.5 Host- und IP-Adressen
Pfeil 18.5.1 Lebt der Rechner?
Pfeil 18.5.2 IP-Adresse des lokalen Hosts
Pfeil 18.5.3 Das Netz ist Klasse …
Pfeil 18.6 NetworkInterface
Pfeil 18.7 Mit dem Socket zum Server
Pfeil 18.7.1 Das Netzwerk ist der Computer
Pfeil 18.7.2 Sockets
Pfeil 18.7.3 Eine Verbindung zum Server aufbauen
Pfeil 18.7.4 Server unter Spannung: die Ströme
Pfeil 18.7.5 Die Verbindung wieder abbauen
Pfeil 18.7.6 Informationen über den Socket
Pfeil 18.7.7 Reine Verbindungsdaten über SocketAddress
Pfeil 18.8 Client-Server-Kommunikation
Pfeil 18.8.1 Warten auf Verbindungen
Pfeil 18.8.2 Ein Multiplikationsserver
Pfeil 18.8.3 Blockierendes Lesen
Pfeil 18.8.4 Von außen erreichbar sein
Pfeil 18.9 Apache Jakarta Commons HttpClient und Net
Pfeil 18.9.1 Jakarta Commons HttpClient
Pfeil 18.9.2 Jakarta Commons Net
Pfeil 18.10 Arbeitsweise eines Webservers
Pfeil 18.10.1 Das Hypertext Transfer Protocol (HTTP)
Pfeil 18.10.2 Anfragen an den Server
Pfeil 18.10.3 Die Antworten vom Server
Pfeil 18.10.4 Webserver mit com.sun.net.httpserver.HttpServer
Pfeil 18.11 Datagram-Sockets
Pfeil 18.11.1 Die Klasse DatagramSocket
Pfeil 18.11.2 Datagramme und die Klasse DatagramPacket
Pfeil 18.11.3 Auf ein hereinkommendes Paket warten
Pfeil 18.11.4 Ein Paket zum Senden vorbereiten
Pfeil 18.11.5 Methoden der Klasse DatagramPacket
Pfeil 18.11.6 Das Paket senden
Pfeil 18.12 E-Mail
Pfeil 18.12.1 Wie eine E-Mail um die Welt geht
Pfeil 18.12.2 Das Simple Mail Transfer Protocol und RFC 822
Pfeil 18.12.3 POP (Post Office Protocol)
Pfeil 18.12.4 Die JavaMail API
Pfeil 18.12.5 E-Mails mittels POP3 abrufen
Pfeil 18.12.6 E-Mails versenden
Pfeil 18.12.7 Ereignisse und Suchen
Pfeil 18.13 Tiefer liegende Netzwerkeigenschaften
Pfeil 18.13.1 Internet Control Message Protocol (ICMP)
Pfeil 18.13.2 MAC-Adresse
Pfeil 18.14 Zum Weiterlesen


Galileo Computing - Zum Seitenanfang

18.8 Client-Server-Kommunikation Zur nächsten ÜberschriftZur vorigen Überschrift

Bevor wir weitere Dienste untersuchen, wollen wir einen kleinen Server programmieren. Server horchen an ihrem zugewiesenen Port auf Anfragen und Eingaben. Ein Server wird durch die Klasse ServerSocket repräsentiert. Der Konstruktor bekommt einfach die Port-Nummer, zu der sich Clients verbinden können, als Argument übergeben.


Beispiel Wir richten einen Server ein, der am Port 1234 horcht:

ServerSocket serverSocket = new ServerSocket( 1234 );

Natürlich müssen wir unserem Client eine noch nicht zugewiesene Port-Adresse zuteilen, andernfalls ist uns eine IOException sicher. Damit der eigene Java-Server nicht mit einem anderen Server in Konflikt gerät, sollten wir einen Blick auf die aktuell laufenden Dienste werfen. Unter Windows listet auf der Kommandozeile netstat -a die laufenden Serverdienste und die belegten Ports auf. Bei Unix-Systemen können nur Root-Besitzer Ports unter 1024 nutzen. Unter dem herkömmlichen Windows ist das egal. Läuft ein Server unendlich, so muss darauf geachtet werden, eine alte Instanz erst zu beenden, damit er neu gestartet werden kann.


Galileo Computing - Zum Seitenanfang

18.8.1 Warten auf Verbindungen Zur nächsten ÜberschriftZur vorigen Überschrift

Nachdem der Socket eingerichtet ist, kann er auf hereinkommende Meldungen reagieren. Mit der blockierenden Methode accept() der ServerSocket-Klasse nehmen wir genau eine wartende Verbindung an:

Socket client = serverSocket.accept();

Nun können wir mit dem zurückgegebenen Client-Socket genauso verfahren wie mit dem schon programmierten Client. Das heißt: Wir öffnen Ein- und Ausgabekanäle und kommunizieren. In der Regel wird ein Thread den Client-Socket annehmen, damit der Server schnell wieder verfügbar ist und neue Verbindungen annehmen und verarbeiten kann.

Wichtig bleibt zu bemerken, dass die Konversation nicht über den Server-Socket selbst läuft. Dieser ist immer noch aktiv und horcht auf eingehende Anfragen. Die accept()-Methode sitzt daher oft in einer Endlosschleife und erzeugt für jeden Hörer einen Thread. Die Schritte, die also jeder Server vollzieht, sind folgende:

1. Einen Server-Socket erzeugen, der horcht.
2. Mit der accept()-Methode auf neue Verbindungen warten.
3. Ein- und Ausgabestrom vom zurückgegebenen Socket erzeugen.
4. Mit einem definierten Protokoll die Konversation unterhalten.
5. Stream von Client und Socket schließen.
6. Bei Schritt 2 weitermachen oder Server-Socket schließen

Der Server wartet auch nicht ewig

Soll der Server nur eine gewisse Zeit auf einkommende Nachrichten warten, so lässt sich ein Timeout einstellen. Dazu ist der Methode setSoTimeout() die Anzahl der Millisekunden zu übergeben. Nimmt der Server dann keine Fragen entgegen, bricht die Verarbeitung mit einer InterruptedIOException ab. Diese Exception gilt für alle Ein- und Ausgabe-Operationen und ist daher auch eine Ausnahme, die nicht im Net-Paket, sondern im IO-Paket deklariert ist.


Beispiel Der Server soll höchstens eine Minute lang auf eingehende Verbindungen warten:

ServerSocket serverSocket = new ServerSocket( port ); 
// Timeout nach 1 Minute 
server.setSoTimeout( 60000 ); 
try { 
  Socket client = server.accept(); 
} catch ( InterruptedIOException e ) { 
  System.err.println( "Timeout after one minute" ); 
}


Galileo Computing - Zum Seitenanfang

18.8.2 Ein Multiplikationsserver Zur nächsten ÜberschriftZur vorigen Überschrift

Der erste Server, den wir programmieren wollen, soll zwei Zahlen multiplizieren. Nach dem Aufbau eines ServerSocket-Objekts soll der Server mit accept() auf einen interessierten Client warten. Nach der akzeptierten Verbindung soll handleConnection() das Protokoll und die Logik übernehmen: Im Eingabestrom werden zwei Zahlen in der String-Repräsentation erwartet, die multipliziert zurückzuschreiben sind.

Listing 18.12 com/tutego/insel/net/MulServer.java

package com.tutego.insel.net; 
 
import java.io.*; 
import java.net.*; 
 
public class MulServer 
{ 
  private static void handleConnection( Socket client ) throws IOException 
  { 
    Scanner     in  = new Scanner( client.getInputStream() ); 
    PrintWriter out = new PrintWriter( client.getOutputStream(), true ); 
 
    String factor1 = in.nextLine(); 
    String factor2 = in.nextLine(); 
 
    out.println( new BigInteger(factor1).multiply( new BigInteger(factor2) ) ); 
  } 
  public static void main( String[] args ) throws IOException 
  { 
    ServerSocket server = new ServerSocket( 3141 ); 
 
    while ( true ) 
    { 
      Socket client = null; 
 
      try 
      { 
        client = server.accept(); 
        handleConnection ( client ); 
      } 
      catch ( IOException e ) { 
        e.printStackTrace(); 
      } 
      finally { 
        if ( client != null ) 
          try { client.close(); } catch ( IOException e ) { } 
      } 
    } 
  } 
}

Kommt es zu einem Verbindungsaufbau, erfragt der Server die Kommunikationsströme, um mit dem Client Daten auszutauschen. Diese einfachen Byte-orientierten InputStream- und OutputStream-Ströme erweitern wir zum Scanner und PrintWriter, sodass wir Zeichenketten statt rohe Bytes lesen und schreiben können. Im Eingabestrom werden dann zwei Zeichenfolgen erwartet; die blockierende nextLine()-Methode übernimmt diese Aufgabe. Kommen die Bytes der Zeichenkette nicht an, wartet der Server ewig auf seine Daten und ist unterdessen blockiert, da er in dieser Implementierung nur einen Client bedient. Bekommt er jedoch die beiden Zeichenfolgen, konvertiert er sie zu einem BigInteger, führt eine Multiplikation durch und sendet das Ergebnis als String zurück. Nach dem Senden ist das Protokoll beendet, und die Verbindung zum Client kann unterbrochen werden. Durch die Endlosschleife ist der Server bereit für neue Anfragen.


Hinweis Werden Ströme eingesetzt, die in irgendeiner Weise puffern, wie PrintWriter, BufferedWriter oder BufferedOutputStream, müssen wir uns bewusst sein, dass die Informationen im Puffer mitunter zwischengespeichert und insofern nicht direkt zum anderen Rechner übertragen werden. In einem Frage-Antwort-Szenario muss der Server oder Client die Anfrage direkt übertragen, und die Nachricht darf nicht im Puffer verweilen. Zu passenden Zeitpunkten müssen die flush()-Methoden der Puffer-Klassen die intern gespeicherten Daten verschicken, damit die Kommunikation weitergeht. Wird im Konstruktor von PrintWriter ein true übergeben, horcht die Klasse auf eine Newline im String und führt automatisch ein flush() durch.


Auf der anderen Seite steht der Client, der aktiv eine Verbindung zum Server aufbaut. Er nutzt ein mit Internet-Adresse und Port initialisiertes Socket-Objekt, um den ein- und ausgehenden Datenstrom zu erfragen und zwei Zeichenfolgen zu übertragen. Der Client wartet auf das Ergebnis und gibt es auf dem Bildschirm aus. Nach der Kommunikation wird die Verbindung geschlossen, um die nötigen Ressourcen wieder freizugeben.

Listing 18.13 com/tutego/insel/net/MulClient.java

package com.tutego.insel.net; 
 
import java.net.*; 
import java.io.*; 
 
class MulClient 
{ 
  public static void main( String[] args ) 
  { 
    Socket server = null; 
 
    try 
    { 
      server = new Socket( "localhost", 3141 ); 
      Scanner     in  = new Scanner( server.getInputStream() ); 
      PrintWriter out = new PrintWriter( server.getOutputStream(), true ); 
 
      out.println( "2" ); 
      out.println( "4" ); 
      System.out.println( in.nextLine() ); 
 
      server = new Socket( "localhost", 3141 ); 
      in  = new Scanner( server.getInputStream() ); 
      out = new PrintWriter( server.getOutputStream(), true ); 
 
      out.println( "23895737895" ); 
      out.println( "434589358935857" ); 
      System.out.println( in.nextLine() ); 
    } 
    catch ( UnknownHostException e ) { 
      e.printStackTrace(); 
    } 
    catch ( IOException e ) { 
      e.printStackTrace(); 
    } 
    finally 
    { 
      if ( server != null ) 
        try { server.close(); } catch ( IOException e ) { } 
    } 
  } 
}

Erweiterung durch Multithreading

Ein anderer Punkt ist die Tatsache, dass Server im Allgemeinen multithreaded ausgelegt sind, damit sie mehrere Anfragen gleichzeitig ausführen können. Der Server erzeugt nicht pro Anfrage einen Thread – dies ist relativ teuer –, sondern nimmt die Threads aus einem Thread-Pool. Mit der Thread-Pool-Klasse aus der Java-Bibliothek lässt sich die Aufgabe vorzüglich bewältigen.


Galileo Computing - Zum Seitenanfang

18.8.3 Blockierendes Lesen Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Eigenschaft ist bei der Server-Programmierung zu beachten: Erwartet der Client aus dem InputStream Daten, schickt der Server aber keine, dann blockiert die Methode. Aus dieser Sackgasse gibt es zwei Auswege: das einfache Schließen des Sockets mit close() und der völlig unterschiedliche Ansatz mit NIO. Wenn der Socket geschlossen wird, werden alle Datenstrom-Operationen abgebrochen, und eine IOException wird ausgelöst.

Damit ist ein gutes Mittel gefunden, um wenigstens blockierte Socket-Verbindungen wieder zu befreien. Dies soll auch das nächste Beispiel demonstrieren. Zuerst wird ein nutzloser ServerSocket aufgebaut, der weder etwas annimmt noch etwas schickt. Der Client verbindet sich zum Server und versucht zu lesen. Da aber vom Server kein Zeichen gesendet wird, hängt read() und wartet auf ein Byte. All das läuft in einem Thread ab. Nach dem Start wird zwei Sekunden später der Socket geschlossen, was zum Abbruch von read() und in den Anweisungsblock der Exception-Behandlung führt.

Listing 18.14 com/tutego/insel/net/CloseConnection.java

package com.tutego.insel.net; 
 
import java.io.IOException; 
import java.net.*; 
 
public class CloseConnection 
{ 
  public static void main( String[] args ) throws Exception 
  { 
    new ServerSocket( 12345 );     // Server anmelden 
 
    final Socket t = new Socket( "localhost", 12345 ); 
 
    new Thread( new Runnable() 
    { 
      public void run() 
      { 
        try 
        { 
          System.out.println( "Gleich hängt er!" ); 
          System.out.println( t.getInputStream().read() ); 
          System.out.println( "Hier hängt er!" ); 
        } 
        catch ( IOException e ) 
        { 
          System.out.println( "Blockierung gelöst" ); 
        } 
      } 
    } ).start(); 
 
    Thread.sleep( 2000 ); 
 
    t.close();  // Releases the block 
  } 
}

Die Ausgabe ist:

Gleich hängt er! 
Blockierung gelöst

Galileo Computing - Zum Seitenanfang

18.8.4 Von außen erreichbar sein topZur vorigen Überschrift

Ein Server lässt sich nur auf dem eigenen Rechner starten. Ist der Rechner vom Internet aus erreichbar, können externe Rechner auf ihn zugreifen. Anders sieht es aus, wenn der Rechner eine Internet-Adresse hat, die von außen nicht sichtbar ist, weil er zum Beispiel über einen Router ins Internet geht. Dann vergibt dieser Router eine eigene Adresse – die oft mit 192.168 oder 10 beginnt – und setzt sie per NAT um, sodass unsere private Adresse außen verborgen bleibt. Die Frage ist nun, ob wir trotzdem einen Serverdienst anbieten können.

Diese Möglichkeit gibt es tatsächlich, wenn einige Randbedingungen gegeben sind: Zunächst muss unsere interne IP-Adresse relativ stabil sein – und unsere äußere IP-Adresse vom Router ins Internet ebenso. Dann muss auf dem Router eine Einstellung vorgenommen werden, damit wir auf bestimmten Ports von außen angesprochen werden können. Diese Einstellung sieht bei jedem Router anders aus, und in größeren Unternehmen wird der Sicherheitsverantwortliche dies nicht akzeptieren. Nach der entsprechenden Einstellung benötigen wir eine globale Adresse, die wir weitergeben können. Dies wird keine IP-Adresse sein, sondern ein Name, der über DNS aufgelöst wird. Das ist schon der Trick, weil der konstante Name mit immer unterschiedlichen IP-Adressen verbunden werden kann, was sich daran zeigt, dass wir zum Beispiel mit einem Einwahl-Router immer unterschiedliche IP-Adressen bekommen. Daher heißt diese Technik auch dynamisches DNS. Eine feste URL gibt es bei unterschiedlichen Anbietern oft auch unentgeltlich, zum Beispiel bei http://www.dyndns.com/. Nach dieser Anmeldung lässt sich ein Subname registrieren, sodass etwa unter meinserver.dyndns.com die IP-Adresse des Einwahl-Routers steht. Dieser leitet nach der entsprechenden Einstellung eine Anfrage an unseren Rechner mit unserem Java-Server weiter.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de