Java SE 8 Standard-Bibliothek  
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis


Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 13 Netzwerkprogrammierung
Pfeil 13.1 Grundlegende Begriffe
Pfeil 13.2 URI und URL
Pfeil 13.2.1 Die Klasse URI
Pfeil 13.2.2 Die Klasse URL
Pfeil 13.2.3 Informationen über eine URL *
Pfeil 13.2.4 Der Zugriff auf die Daten über die Klasse URL
Pfeil 13.3 Die Klasse URLConnection *
Pfeil 13.3.1 Methoden und Anwendung von URLConnection
Pfeil 13.3.2 Protokoll- und Content-Handler
Pfeil 13.3.3 Im Detail: Von der URL zur URLConnection
Pfeil 13.3.4 Der Protokoll-Handler für JAR-Dateien
Pfeil 13.3.5 Basic Authentication und Proxy-Authentifizierung
Pfeil 13.4 Mit GET und POST Daten übergeben *
Pfeil 13.4.1 Kodieren der Parameter für Serverprogramme
Pfeil 13.4.2 In Wikipedia suchen und mit GET-Request absenden
Pfeil 13.4.3 POST-Request absenden
Pfeil 13.5 Host- und IP-Adressen
Pfeil 13.5.1 Lebt der Rechner?
Pfeil 13.5.2 IP-Adresse des lokalen Hosts
Pfeil 13.5.3 Das Netz ist klasse *
Pfeil 13.5.4 NetworkInterface
Pfeil 13.6 Mit dem Socket zum Server
Pfeil 13.6.1 Das Netzwerk ist der Computer
Pfeil 13.6.2 Sockets
Pfeil 13.6.3 Eine Verbindung zum Server aufbauen
Pfeil 13.6.4 Server unter Spannung – die Ströme
Pfeil 13.6.5 Die Verbindung wieder abbauen
Pfeil 13.6.6 Informationen über den Socket *
Pfeil 13.6.7 Reine Verbindungsdaten über SocketAddress *
Pfeil 13.7 Client-Server-Kommunikation
Pfeil 13.7.1 Warten auf Verbindungen
Pfeil 13.7.2 Ein Multiplikationsserver
Pfeil 13.7.3 Blockierendes Lesen
Pfeil 13.8 Apache HttpComponents und Commons Net *
Pfeil 13.8.1 HttpComponents
Pfeil 13.8.2 Apache Commons Net
Pfeil 13.9 Arbeitsweise eines Webservers *
Pfeil 13.9.1 Das Hypertext Transfer Protocol (HTTP)
Pfeil 13.9.2 Anfragen an den Server
Pfeil 13.9.3 Die Antworten vom Server
Pfeil 13.9.4 Webserver mit com.sun.net.httpserver.HttpServer
Pfeil 13.10 Verbindungen durch einen Proxy-Server *
Pfeil 13.10.1 System-Properties
Pfeil 13.10.2 Verbindungen durch die Proxy-API
Pfeil 13.11 Datagram-Sockets *
Pfeil 13.11.1 Die Klasse DatagramSocket
Pfeil 13.11.2 Datagramme und die Klasse DatagramPacket
Pfeil 13.11.3 Auf ein hereinkommendes Paket warten
Pfeil 13.11.4 Ein Paket zum Senden vorbereiten
Pfeil 13.11.5 Methoden der Klasse DatagramPacket
Pfeil 13.11.6 Das Paket senden
Pfeil 13.12 E-Mail *
Pfeil 13.12.1 Wie eine Elektropost um die Welt geht
Pfeil 13.12.2 Das Simple Mail Transfer Protocol und RFC 822
Pfeil 13.12.3 POP (Post Office Protocol)
Pfeil 13.12.4 Die JavaMail API
Pfeil 13.12.5 E-Mails mittels POP3 abrufen
Pfeil 13.12.6 Multipart-Nachrichten verarbeiten
Pfeil 13.12.7 E-Mails versenden
Pfeil 13.12.8 Ereignisse und Suchen
Pfeil 13.13 Tiefer liegende Netzwerkeigenschaften *
Pfeil 13.13.1 MAC-Adressen auslesen
Pfeil 13.13.2 Internet Control Message Protocol (ICMP)
Pfeil 13.14 Zum Weiterlesen
 
Zum Seitenanfang

13.7Client-Server-Kommunikation Zur vorigen ÜberschriftZur nächsten Ü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.

[zB]Beispiel

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

try ( ServerSocket serverSocket = new ServerSocket( 1234 ) ) {

}

Auch ein ServerSocket sollte nach dem Benutzen geschlossen werden. Die Klasse implementiert Closeable, ist also ein AutoCloseable und perfekt in einem try mit Ressourcen platziert.

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 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.

class java.net.ServerSocket
implements Closeable
  • ServerSocket(int port) throws IOException
    Initialisiert einen ServerSocket für den angegebenen Port, wobei port zwischen 0 und 65536 liegen muss. Ist port gleich 0, weist das Betriebssystem selbst einen freien Port zu.

 
Zum Seitenanfang

13.7.1Warten auf Verbindungen Zur vorigen ÜberschriftZur nächsten Ü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(int) 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.

[zB]Beispiel

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

try ( ServerSocket serverSocket = new ServerSocket( port ) ) {
serverSocket.setSoTimeout( 60000 ); // Timeout nach 1 Minute
Socket clientSocket = serverSocket.accept();

}
catch ( InterruptedIOException e ) {
System.err.println( "Timeout nach einer Minute!" );
}
 
Zum Seitenanfang

13.7.2Ein Multiplikationsserver Zur vorigen ÜberschriftZur nächsten Ü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 die eigene Methode handleConnection(Socket) das Protokoll und die Logik übernehmen: Im Eingabestrom werden zwei Zahlen in der String-Repräsentation erwartet, die multipliziert zurückzuschreiben sind:

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

package com.tutego.insel.net;

import java.io.*;
import java.math.BigInteger;
import java.net.*;
import java.util.Scanner;

public class MulServer {

public static void main( String[] args ) throws IOException {
try ( ServerSocket server = new ServerSocket( 3141 ) ) {
while ( true )
try ( Socket client = server.accept() ) {
handleConnection( client );
}
catch ( IOException e ) {
e.printStackTrace();
}
}
}

@SuppressWarnings( "resource" ) // Socket wird in main() geschlossen
private static void handleConnection( Socket client ) throws IOException {
Scanner in = new Scanner( client.getInputStream(), StandardCharsets.UTF_8.name() );
String factor1 = in.nextLine();
String factor2 = in.nextLine();
PrintWriter out = new PrintWriter(
new OutputStreamWriter( client.getOutputStream(),
StandardCharsets.UTF_8.name() ), true );
out.println( new BigInteger( factor1 ).multiply( new BigInteger( factor2 ) ) );
}
}

Kommt es zu einem Verbindungsaufbau, erfragt der Server die Kommunikationsströme, um mit dem Client Daten auszutauschen. Diese einfachen byteorientierten InputStream- und OutputStream-Ströme erweitern wir zum Scanner und PrintWriter, sodass wir Zeichenketten statt roher 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 ein Zeilenumbruch 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 Internetadresse 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 13.17com/tutego/insel/net/MulClient.java

package com.tutego.insel.net;

import java.io.*;
import java.net.*;
import java.util.Scanner;

class MulClient {

@SuppressWarnings( "resource" ) // try mit Ressourcen schließt Socket
public static void main( String[] args ) throws IOException {

// Berechne 2 * 4
try ( Socket socket = new Socket( "localhost", 3141 ) ) {
Scanner in = new Scanner( socket.getInputStream(),
StandardCharsets.UTF_8.name() );
PrintWriter out = new PrintWriter(
new OutputStreamWriter( socket.getOutputStream(),
StandardCharsets.UTF_8.name() ), true );

out.println( "2" );
out.println( "4" );
System.out.println( in.nextLine() );
}

// Berechne 23895737895 * 434589358935857
try ( Socket socket = new Socket( "localhost", 3141 ) ) {
Scanner in = new Scanner( socket.getInputStream(),
StandardCharsets.UTF_8.name() );
PrintWriter out = new PrintWriter(
new OutputStreamWriter( socket.getOutputStream(),
StandardCharsets.UTF_8.name() ), true );

out.println( "23895737895" );
out.println( "434589358935857" );
System.out.println( in.nextLine() );
}
}
}

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.

 
Zum Seitenanfang

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

Eine Eigenschaft ist bei der Serverprogrammierung 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 2 Sekunden später der Socket geschlossen, was zum Abbruch von read() und in den Anweisungsblock der Exception-Behandlung führt:

Listing 13.18com/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 socket = new Socket( "localhost", 12345 );

new Thread( new Runnable() {
@Override public void run() {
try {
System.out.println( "Gleich hängt er!" );
System.out.println( socket.getInputStream().read() );
System.out.println( "Hier hängt er!" );
}
catch ( IOException e ) {
System.out.println( "Blockierung gelöst" );
}
}
} ).start();

Thread.sleep( 2000 );

socket.close(); // Blockierung auflösen
}
}

Die Ausgabe ist:

Gleich hängt er!
Blockierung gelöst

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018. Original - https://www.rheinwerk-verlag.de/openbook/
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.

 

 
 


29.09.2022 - Sitemap.xml