9. Programmquellcode
9.1. Der generische TCP-Client
Viele Dienste, die in den Anfängen des Internets entstanden sind, funktionieren nach dem zuvor behandelten Echo-Server-Modell: Der Austausch zwischen Client und Server besteht aus dem Austausch von Textzeilen. Wir werden einen generischen TCP-Client schreiben, der wie folgt gestartet wird: java cltTCPgenerique server port
Dieser TCP-Client stellt eine Verbindung zum Port des Servers her. Sobald die Verbindung hergestellt ist, erstellt er zwei Threads:
- einen Thread, der für das Einlesen der über die Tastatur eingegebenen Befehle und deren Übermittlung an den Server zuständig ist
- ein Thread, der für das Lesen der Antworten des Servers und deren Anzeige auf dem Bildschirm zuständig ist
Warum zwei Threads? Jeder TCP-IP-Dienst hat sein eigenes spezifisches Protokoll, und es treten manchmal folgende Situationen auf:
- Der Client muss mehrere Zeilen Text senden, bevor er eine Antwort erhält
- Die Antwort eines Servers kann mehrere Zeilen Text enthalten
Daher ist die Schleife, die eine einzelne Zeile an den Server sendet und eine einzelne Zeile vom Server empfängt, nicht immer geeignet. Wir werden daher zwei separate Schleifen erstellen:
- eine Schleife zum Lesen der über die Tastatur eingegebenen Befehle, die an den Server gesendet werden sollen. Der Benutzer signalisiert das Ende der Befehle mit dem Schlüsselwort „fin“.
- eine Schleife zum Empfangen und Anzeigen der Antworten des Servers. Dabei handelt es sich um eine Endlosschleife, die nur unterbrochen wird, wenn der Server die Netzwerkverbindung trennt oder der Benutzer den Befehl „end“ über die Tastatur eingibt.
Um diese beiden separaten Schleifen zu haben, benötigen wir zwei unabhängige Threads. Betrachten wir ein Ausführungsbeispiel, bei dem unser generischer TCP-Client eine Verbindung zu einem SMTP-Dienst (Simple Mail Transfer Protocol) herstellt. Dieser Dienst ist für die Weiterleitung von E-Mails an ihre Empfänger zuständig. Er läuft auf Port 25 und verwendet ein textbasiertes Austauschprotokoll.
Dos>java clientTCPgenerique istia.univ-angers.fr 25
Commandes :
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
help
<-- 502 5.3.0 Sendmail 8.11.6 -- HELP not implemented
mail from: machin@univ-angers.fr
<-- 250 2.1.0 machin@univ-angers.fr... Sender ok
rcpt to: serge.tahe@istia.univ-angers.fr
<-- 250 2.1.5 serge.tahe@istia.univ-angers.fr... Recipient ok
data
<-- 354 Enter mail, end with "." on a line by itself
Subject: test
ligne1
ligne2
ligne3
.
<-- 250 2.0.0 g4D6bks25951 Message accepted for delivery
quit
<-- 221 2.0.0 istia.univ-angers.fr closing connection
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Lassen Sie uns diese Client-Server-Kommunikation kommentieren:
- Der SMTP-Dienst sendet eine Willkommensnachricht, wenn ein Client eine Verbindung zu ihm herstellt:
- Einige Dienste verfügen über einen „help“-Befehl, der Informationen zu den für diesen Dienst verfügbaren Befehlen liefert. Das ist hier nicht der Fall. Die im Beispiel verwendeten SMTP-Befehle lauten wie folgt:
- mail from: Absender, um die E-Mail-Adresse des Absenders anzugeben
- rcpt to: Empfänger, um die E-Mail-Adresse des Empfängers der Nachricht anzugeben. Bei mehreren Empfängern wird der Befehl rcpt to: so oft wie nötig für jeden Empfänger wiederholt.
- data, das dem SMTP-Server signalisiert, dass die Nachricht versendet werden soll. Wie in der Antwort des Servers angegeben, handelt es sich hierbei um eine Folge von Zeilen, die mit einer Zeile endet, die nur einen Punkt enthält. Eine Nachricht kann Kopfzeilen enthalten, die durch eine Leerzeile vom Nachrichtentext getrennt sind. In unserem Beispiel haben wir einen Betreff mit dem Schlüsselwort Subject: eingefügt
- Sobald die Nachricht gesendet wurde, können wir dem Server mit dem Befehl „quit“ mitteilen, dass wir fertig sind. Der Server schließt daraufhin die Netzwerkverbindung. Der Lese-Thread kann dieses Ereignis erkennen und anhalten.
- Der Benutzer gibt dann „end“ über die Tastatur ein, um auch den Thread zu stoppen, der die über die Tastatur eingegebenen Befehle liest.
Wenn wir die empfangene E-Mail überprüfen, sehen wir Folgendes (Outlook):

Beachten Sie, dass der SMTP-Dienst nicht erkennen kann, ob ein Absender gültig ist oder nicht. Daher können Sie dem Feld „Von“ einer Nachricht niemals vertrauen. In diesem Fall existierte die Absender-E-Mail-Adresse machin@univ-angers.fr nicht.
Dieser generische TCP-Client ermöglicht es uns, das Kommunikationsprotokoll von Internetdiensten zu ermitteln und darauf aufbauend spezialisierte Klassen für Clients dieser Dienste zu erstellen. Sehen wir uns das Kommunikationsprotokoll des POP-Dienstes (Post Office Protocol) an, mit dem wir auf einem Server gespeicherte E-Mails abrufen können. Er läuft auf Port 110.
Dos> java clientTCPgenerique istia.univ-angers.fr 110
Commandes :
<-- +OK Qpopper (version 4.0.3) at istia.univ-angers.fr starting.
help
<-- -ERR Unknown command: "help".
user st
<-- +OK Password required for st.
pass monpassword
<-- +OK st has 157 visible messages (0 hidden) in 11755927 octets.
list
<-- +OK 157 visible messages (11755927 octets)
<-- 1 892847
<-- 2 171661
...
<-- 156 2843
<-- 157 2796
<-- .
retr 157
<-- +OK 2796 octets
<-- Received: from lagaffe.univ-angers.fr (lagaffe.univ-angers.fr [193.49.144.1])
<-- by istia.univ-angers.fr (8.11.6/8.9.3) with ESMTP id g4D6wZs26600;
<-- Mon, 13 May 2002 08:58:35 +0200
<-- Received: from jaume ([193.49.146.242])
<-- by lagaffe.univ-angers.fr (8.11.1/8.11.2/GeO20000215) with SMTP id g4D6wSd37691;
<-- Mon, 13 May 2002 08:58:28 +0200 (CEST)
...
<-- ------------------------------------------------------------------------
<-- NOC-RENATER2 Tl. : 0800 77 47 95
<-- Fax : (+33) 01 40 78 64 00 , Email : noc-r2@cssi.renater.fr
<-- ------------------------------------------------------------------------
<--
<-- .
quit
<-- +OK Pop server at istia.univ-angers.fr signing off.
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Die wichtigsten Befehle lauten wie folgt:
- user login, wobei Sie Ihren Benutzernamen auf dem Rechner eingeben, der Ihre E-Mails hostet
- pass password, wo Sie das Passwort eingeben, das mit dem vorherigen Login verknüpft ist
- list, um eine Liste der Nachrichten im Format Nummer, Größe in Byte abzurufen
- retr i, um die Nachricht Nummer i zu lesen
- quit, um die Sitzung zu beenden.
Betrachten wir nun das Kommunikationsprotokoll zwischen einem Client und einem Webserver, der in der Regel auf Port 80 läuft:
Dos> java clientTCPgenerique istia.univ-angers.fr 80
Commandes :
GET /index.html HTTP/1.0
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
<--
<-- <head>
<-- <meta http-equiv="Content-Type"
<-- content="text/html; charset=iso-8859-1">
<-- <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<-- <title>Bienvenue a l'ISTIA - Universite d'Angers</title>
<-- </head>
....
<-- face="Verdana"> - Dernire mise jour le <b>10 janvier 2002</b></font></p>
<-- </body>
<-- </html>
<--
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Ein Web-Client sendet seine Befehle nach folgendem Muster an den Server:
Der Webserver antwortet erst, nachdem er die Leerzeile empfangen hat. In diesem Beispiel haben wir nur einen Befehl verwendet:
der die URL /index.html vom Server anfordert und angibt, dass HTTP Version 1.0 verwendet wird. Die aktuellste Version dieses Protokolls ist 1.1. Das Beispiel zeigt, dass der Server mit dem Inhalt der Datei index.html geantwortet und anschließend die Verbindung geschlossen hat, wie wir an der Meldung „thread terminating“ in der Antwort erkennen können. Vor dem Senden des Inhalts der Datei index.html hat der Webserver eine Reihe von Headern gesendet, gefolgt von einer Leerzeile:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
Die Zeile <html> ist die erste Zeile der Datei /index.html. Der vorangehende Text wird als HTTP-Header (HyperText Transfer Protocol) bezeichnet. Wir werden hier nicht näher auf diese Header eingehen, aber denken Sie daran, dass unser generischer Client Zugriff darauf bietet, was für das Verständnis hilfreich sein kann. Zum Beispiel die erste Zeile:
bedeutet, dass der kontaktierte Webserver das HTTP/1.1-Protokoll unterstützt und die angeforderte Datei erfolgreich gefunden hat (200 OK), wobei 200 ein HTTP-Antwortcode ist. Die Zeilen
Teilen Sie dem Client mit, dass er 11.251 Byte HTML-Text (HyperText Markup Language) erhalten wird und dass die Verbindung geschlossen wird, sobald die Daten gesendet wurden.
Hier haben wir also einen sehr praktischen TCP-Client. Er kann zwar weniger als das zuvor verwendete Telnet-Programm, aber es war interessant, ihn selbst zu schreiben. Das generische TCP-Client-Programm sieht wie folgt aus:
// imported packages
import java.io.*;
import java.net.*;
public class clientTCPgenerique{
// receives the characteristics of a service as a parameter in the form
// server port
// connects to the service
// creates a thread to read keyboard commands
// these will be sent to the
// creates a thread to read server responses
// these will be displayed on the screen
// the whole thing ends with the command end typed on the keyboard
// instance variable
private static Socket client;
public static void main(String[] args){
// syntax
final String syntaxe="pg serveur port";
// number of arguments
if(args.length != 2)
erreur(syntaxe,1);
// note the server name
String serveur=args[0];
// port must be integer >0
int port=0;
boolean erreurPort=false;
Exception E=null;
try{
port=Integer.parseInt(args[1]);
}catch(Exception e){
E=e;
erreurPort=true;
}
erreurPort=erreurPort || port <=0;
if(erreurPort)
erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);
client=null;
// there may be problems
try{
// connect to the service
client=new Socket(serveur,port);
}catch(Exception ex){
// error
erreur("Impossible de se connecter au service ("+ serveur
+","+port+"), erreur : "+ex.getMessage(),3);
// end
return;
}//catch
// create read/write threads
new ClientSend(client).start();
new ClientReceive(client).start();
// end thread main
return;
}// hand
// error display
public static void erreur(String msg, int exitCode){
// error display
System.err.println(msg);
// stop with error
System.exit(exitCode);
}//error
}//class
class ClientSend extends Thread {
// class for reading keyboard commands
// and send them to a server via a tcp client passed in parameter
private Socket client; // tcp client
// manufacturer
public ClientSend(Socket client){
// we note the tcp client
this.client=client;
}//manufacturer
// thread Run method
public void run(){
// local data
PrintWriter OUT=null; // network write streams
BufferedReader IN=null; // keyboard flow
String commande=null; // command read from keyboard
// error management
try{
// network write stream creation
OUT=new PrintWriter(client.getOutputStream(),true);
// keyboard input stream creation
IN=new BufferedReader(new InputStreamReader(System.in));
// order entry-send loop
System.out.println("Commandes : ");
while(true){
// read command typed on keyboard
commande=IN.readLine().trim();
// finished?
if (commande.toLowerCase().equals("fin")) break;
// send order to server
OUT.println(commande);
// next order
}//while
}catch(Exception ex){
// error
System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// end - close flows
try{
OUT.close();client.close();
}catch(Exception ex){}
// signals the end of the thread
System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
}//run
}//class
class ClientReceive extends Thread{
// class responsible for reading lines of text intended for a
// tcp client passed as parameter
private Socket client; // tcp client
// manufacturer
public ClientReceive(Socket client){
// we note the tcp client
this.client=client;
}//manufacturer
// thread Run method
public void run(){
// local data
BufferedReader IN=null; // network read stream
String réponse=null; // server response
// error management
try{
// create network read stream
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// loop read text lines from IN stream
while(true){
// network streaming
réponse=IN.readLine();
// closed flow?
if(réponse==null) break;
// display
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// error
System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// end - we close the feeds
try{
IN.close();client.close();
}catch(Exception ex){}
// signals the end of the thread
System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
}//run
}//class
9.2. Der generische TCP-Server
Nun sehen wir uns einen Server an
- , der die von seinen Clients gesendeten Befehle auf dem Bildschirm anzeigt
- und ihnen als Antwort die Textzeilen sendet, die ein Benutzer über die Tastatur eingegeben hat. Es ist also der Benutzer, der als Server fungiert.
Das Programm wird gestartet mit: java genericTCPserver listeningPort, wobei listeningPort der Port ist, mit dem sich die Clients verbinden müssen. Der Client-Dienst wird von zwei Threads abgewickelt:
- ein Thread, der ausschließlich für das Lesen der vom Client gesendeten Textzeilen zuständig ist
- ein Thread, der ausschließlich dem Lesen der vom Benutzer über die Tastatur eingegebenen Antworten gewidmet ist. Dieser Thread signalisiert mithilfe des Befehls `fin`, dass er die Verbindung zum Client schließt.
Der Server erstellt zwei Threads pro Client. Bei n Clients sind somit 2n Threads gleichzeitig aktiv. Der Server selbst wird nicht beendet, es sei denn, der Benutzer drückt die Tastenkombination Strg-C auf der Tastatur. Sehen wir uns einige Beispiele an.
Der Server läuft auf Port 100, und wir verwenden den generischen Client, um mit ihm zu kommunizieren. Das Client-Fenster sieht wie folgt aus:
E:\data\serge\MSNET\c#\réseau\client tcp générique> java clientTCPgenerique localhost 100
Commandes :
commande 1 du client 1
<-- réponse 1 au client 1
commande 2 du client 1
<-- réponse 2 au client 1
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]
Zeilen, die mit <-- beginnen, stammen vom Server und sind an den Client gesendet; die anderen stammen vom Client und sind an den Server gesendet. Das Serverfenster sieht wie folgt aus:
Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
Zeilen, die mit <-- beginnen, sind vom Client an den Server gesendet. Zeilen N: sind vom Server an Client N gesendet. Der oben genannte Server ist weiterhin aktiv, obwohl Client 1 beendet ist. Wir starten einen zweiten Client für denselben Server:
Dos> java clientTCPgenerique localhost 100
Commandes :
commande 3 du client 2
<-- réponse 3 au client 2
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]
Das Serverfenster sieht dann wie folgt aus:
Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- commande 3 du client 2
réponse 3 au client 2
2 : [fin du Thread de lecture des demandes du client 2]
fin
[fin du Thread de lecture des réponses du serveur au client 2]
^C
Simulieren wir nun einen Webserver, indem wir unseren generischen Server auf Port 88 ausführen:
Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Öffnen wir nun einen Browser und rufen die URL http://localhost:88/exemple.html auf. Der Browser stellt dann eine Verbindung zu Port 88 auf dem Localhost-Rechner her und fordert die Seite /example.html an:

Schauen wir uns nun unser Serverfenster an:
Dos>java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- GET /exemple.html HTTP/1.1
<-- Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, */*
<-- Accept-Language: fr
<-- Accept-Encoding: gzip, deflate
<-- User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2
914)
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
Hier werden die vom Browser gesendeten HTTP-Header angezeigt. So können wir nach und nach mehr über das HTTP-Protokoll lernen. In einem früheren Beispiel haben wir einen Web-Client erstellt, der lediglich den GET-Befehl gesendet hat. Das war ausreichend. Hier sehen wir, dass der Browser weitere Informationen an den Server sendet. Diese Informationen sollen dem Server mitteilen, um welche Art von Client es sich handelt. Wir sehen außerdem, dass die HTTP-Header mit einer Leerzeile enden.
Erstellen wir eine Antwort für unseren Client. Der Benutzer am Bildschirm ist hier der eigentliche Server und kann manuell eine Antwort erstellen. Erinnern Sie sich an die Antwort, die ein Webserver in einem früheren Beispiel gesendet hat:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
Versuchen wir, eine ähnliche Antwort zu geben:
...
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
2 : HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
2 : <html>
2 : <head><title>Serveur generique</title></head>
2 : <body>
2 : <center>
2 : <h2>Reponse du serveur generique</h2>
2 : </center>
2 : </body>
2 : </html>
2 : fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du Thread de lecture des demandes du client 2]
[fin du Thread de lecture des réponses du serveur au client 2]
Zeilen, die mit 2: beginnen, werden vom Server an Client Nr. 2 gesendet. Der Befehl „end“ schließt die Verbindung vom Server zum Client. In unserer Antwort haben wir uns auf die folgenden HTTP-Header beschränkt:
HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
Wir geben die Größe der zu sendenden Datei (Content-Length) nicht an, sondern weisen lediglich darauf hin, dass wir die Verbindung (Connection: close) nach dem Senden schließen werden. Dies reicht für den Browser aus. Sobald er sieht, dass die Verbindung geschlossen wurde, weiß er, dass die Antwort des Servers vollständig ist, und zeigt die ihm gesendete HTML-Seite an. Die Seite sieht wie folgt aus:
2 : <html>
2 : <head><title>Serveur generique</title></head>
2 : <body>
2 : <center>
2 : <h2>Reponse du serveur generique</h2>
2 : </center>
2 : </body>
2 : </html>
Der Benutzer schließt dann die Verbindung zum Client, indem er den Befehl „fin“ eingibt. Der Browser erkennt daraufhin, dass die Antwort des Servers vollständig ist, und kann sie anzeigen:

Wenn Sie im obigen Beispiel „Ansicht/Quelltext“ auswählen, um zu sehen, was der Browser empfangen hat, erhalten Sie:

das heißt, genau das, was vom generischen Server gesendet wurde.
Der Code für den generischen TCP-Server lautet wie folgt:
// packages
import java.io.*;
import java.net.*;
public class serveurTCPgenerique{
// main program
public static void main (String[] args){
// receives the port of listening to customer requests
// creates a thread to read client requests
// these will be displayed on the screen
// creates a thread to read keyboard commands
// these will be sent as a reply to the customer
// the whole thing ends with the command end typed on the keyboard
final String syntaxe="Syntaxe : pg port";
// instance variable
// is there an argument
if(args.length != 1)
erreur(syntaxe,1);
// port must be integer >0
int port=0;
boolean erreurPort=false;
Exception E=null;
try{
port=Integer.parseInt(args[0]);
}catch(Exception e){
E=e;
erreurPort=true;
}
erreurPort=erreurPort || port <=0;
if(erreurPort)
erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);
// we create the listening service
ServerSocket ecoute=null;
int nbClients=0; // no. of customers handled
try{
// create the service
ecoute=new ServerSocket(port);
// follow-up
System.out.println("Serveur générique lancé sur le port " + port);
// customer service loop
Socket client=null;
while (true){ // infinite loop - will be stopped by Ctrl-C
// waiting for a customer
client=ecoute.accept();
// the service is provided by separate threads
nbClients++;
// create read/write threads
new ServeurSend(client,nbClients).start();
new ServeurReceive(client,nbClients).start();
// back to listening to requests
}// end while
}catch(Exception ex){
// we report the error
erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
}//catch
}// fine hand
// error display
public static void erreur(String msg, int exitCode){
// error display
System.err.println(msg);
// stop with error
System.exit(exitCode);
}//error
}//class
class ServeurSend extends Thread{
// class responsible for reading typed responses
// and send them to a client via a tcp client passed to the
Socket client; // tcp client
int numClient; // customer no
// manufacturer
public ServeurSend(Socket client, int numClient){
// we note the tcp client
this.client=client;
// and its
this.numClient=numClient;
}//manufacturer
// thread Run method
public void run(){
// local data
PrintWriter OUT=null; // network write streams
String réponse=null; // answer read from keyboard
BufferedReader IN=null; // keyboard flow
// follow-up
System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
// error management
try{
// network write stream creation
OUT=new PrintWriter(client.getOutputStream(),true);
// keyboard flow creation
IN=new BufferedReader(new InputStreamReader(System.in));
// order entry-send loop
while(true){
// customer identification
System.out.print("--> " + numClient + " : ");
// read response typed on keyboard
réponse=IN.readLine().trim();
// finished?
if (réponse.toLowerCase().equals("fin")) break;
// send response to server
OUT.println(réponse);
// following response
}//while
}catch(Exception ex){
// error
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// end - close flows
try{
OUT.close();client.close();
}catch(Exception ex){}
// signals the end of the thread
System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
}//run
}//class
class ServeurReceive extends Thread{
// class responsible for reading text lines sent to the server
// via a tcp client passed to the builder
Socket client; // tcp client
int numClient; // customer no
// manufacturer
public ServeurReceive(Socket client, int numClient){
// we note the tcp client
this.client=client;
// and its
this.numClient=numClient;
}//manufacturer
// thread Run method
public void run(){
// local data
BufferedReader IN=null; // network read stream
String réponse=null; // server response
// follow-up
System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
// error management
try{
// create network read stream
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// loop read text lines from IN stream
while(true){
// network streaming
réponse=IN.readLine();
// closed flow?
if(réponse==null) break;
// display
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// error
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// end - close flows
try{
IN.close();client.close();
}catch(Exception ex){}
// signals the end of the thread
System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
}//run
}//class