CH 3
CH 3
Introduction
Les classes java.net correspondantes aux communications orientées connexion
Les classes java.net communes pour les communications orientées connexion et orientées sans
connexion
Les classes java.net correspondantes aux communications orientées sans connexion
Kechid Mounir
[email protected]
La programmation réseau en Java
Introduction
Le langage java offre l'un de ses aspects les plus originaux, à travers le package Java.net. Ce
package rassemble toutes les classes nécessaires à l'élaboration de programmes réseaux
communiquant via les interfaces Socket. Les classes de java.net peuvent être reparties en deux
principales catégories.
● Les classes pour la communication WEB : Ce sont les classes facilitant les fonctions réseaux
liées aux Word Wide Web, ainsi que les classes liées aux URLs (URL,URL connexion). Cette
catégorie de classes sort du cadre de ce cours et ne sera pas donc abordée.
● Les Classes générales de communication : C'est l‛ensemble de classes qui offre l'accès aux
communications réseau brutes (Communications du niveau socket). Selon le mode de
communication, cet ensemble peut être réparti en trois groupes. Un groupe de classes pour
les communications en mode connexion, un autre pour celles en modes sans connexion et un
troisième commun aux deux types de communication.
Deux classes sont offertes par java pour permettre des communications orientées connexion entre
les programmes distants. La classe java.net.ServerSocket qui est utilisée, normalement, par les
programmes serveur (pour l‛écoute sur un port) et la classe java.net.socket qui est utilisée par les
clients (pour la connexion et la communication) et les serveurs (pour communiquer).
La classe java.net.Socket est utilisée pour la programmation des sockets connectées, côté client et
côté serveur (pour la communication avec les clients connectés comme on va le voir infra).
Les constructeurs :
Cette classe possède six constructeurs.
Exemple :
try
{
// Connexion au serveur http (dont le port est 80) de l‛hôte 192.21 22.23
Socket maSocket = new Socket ( "192.21 22.23", 80);
// ......
// Connexion à un serveur local dont le port est 2000
Socket maSocketLocale = Socket("localhost"[1], 7);
}
catch (Exception e)
{
System.err.println ("Err – " + e);
}
Les méthodes
Les méthodes les plus importante de cette classe sont exposées selon leurs utilités :
La communication effective à travers une socket connectée utilise la notion de flots de données
(java.io.OutputStream et java.io.InputStream). Les deux méthodes suivantes sont utilisées pour
obtenir les flots en entrée et en sortie.
La première méthode renvoie un flux d'entrée pour la socket, qui peut être utilisé pour lire les
octets de données de la socket. La deuxième renvoie un flux de sortie pour la socket qui peut être
utilisé pour écrire les octets dans la socket. L‛exemple suivant montre comment, créer les streams
pour lire et écrire sur la socket (maSocket) et comment les utiliser pour communiquer.
Exemple :
try
{
// Connexion au serveur http de l‛hôte 192.21 22.23
Socket maSocket = new Socket ( "192.21 22.23 ", 80);
// Création du Stream pour lire sur la socket (maSocket)
BufferedReader fEntrant = new BufferedReader (new InputStreamReader (maSocket.
getInputStream() ) );
// Création du Stream pour écrire sur la socket (maSocket)
PrintStream fSortant = new PrintStream( maSocket.getOutputStream() );
...
// Écriture sur maSocket (envoi à ( "192.21 22.23", 80) )
fSortant.println("Bonjour ");
...
// Lecture (des flux reçus de ( "192.21 22.23 ", 80)) sur maSocket
String reception = fEntrant.readLine();
…
}
catch (Exception e)
{
System.err.println ("Error – " + e);
}
Ces méthodes permettent de gérer certaines options pendant une communication connectée, les
noms de ces méthodes, leurs prototypes et leurs rôles sont résumés dans le tableau suivant :
La méthode close :
● Créer la socket
● Créer un flux d‛entrée (input stream) et le relier à la socket créée.
● Lire les données du flux d‛entrée crée et afficher le résultat.
Solution 1 :
1. import java.net.*;
2. import java.io.*;
Q: Si l‛on veut que notre client Daytime ne se bloque pas en attente de la réponse plus que 5
secondes. Que doit-t-on rajouter et où dans le code 1 ?
daytime.setSoTimeout (5000);
Note : Si vous voulez tester le programme DayTimeClient (avec les programmes serveur présentés
infra), n‛oubliez pas d‛effacer les numérotations des lignes du code1.
Cette classe englobe des objets qui représentent l'interface socket (la socket) pour les serveurs
en mode connecté. De telles sockets attendent des connexions de la part des clients, lorsqu'un
client sollicite une connexion, la socket serveur l'accepte en créant (comme on va le voir) une autre
socket de la classe précédente (java.net.socket) pour communiquer avec le client. Donc on peut dire
que ces socket sont des socket d'écoute. Elles ne font qu'accepter des connexions. Aucune
communication effective (échange d‛information) ne se passe à travers elles. Les différents
constructeurs et méthodes de cette classe sont énumérés dans les sous-sections suivantes.
Les constructeurs
Pour un objet ServerSocket deux informations sont essentielles, le numéro de port spécifique sur
lequel écoute la socket (il doit être supérieur à 1024 pour éviter les confusions avec les serveurs
standard qui prennent des numéro de ports entre 0 et 1024) et la longueur maximale de la file
d'attente des connexions entrantes (si cette file est pleine, tout client qui sollicite une connexion
sera rejeté).
Alors que le premier constructeur ne permet de définir que le numéro de port (la longueur de la file
étant prise par défaut égale à 50) le deuxième donne la liberté du choix de cette longueur. Si
l'hôte où réside le serveur contient plusieurs adresses IP, le troisième constructeur donne la
possibilité d'indiquer l'adresse IP à laquelle créer la socket.
Exemple :
try
{
// Attacher la socket au port 80, pour fournir un service orienté connexion
ServerSocket maServer = new ServerSocket ( 80 );
// ......
}
catch (IOException ioe)
{
System.err.println ("I/O error – " + ioe);
}
Les méthodes :
La première méthode retourne l'adresse IP locale sur laquelle est connectée la socket serveur
invoquée et la deuxième permet d'en récupérer le numéro de port local.
La méthode accept :
A la détection d'une demande de connexion d'un client, la méthode accept retourne un objet socket
de la classe java.net.socket (vu supra). C‛est cette socket retournée qui sera utilisée pour la
communication avec le client et pas la socket serveur qui ne fait qu'écouter.
Exemple :
try
{
// Attacher la socket au port 80, pour fournir un service orienté connexion (like
HTTP)
ServerSocket monServeur = new ServerSocket ( 80 );
// Établissement d‛une écoute bloquante pour la lecture de la prochaine
connexion //socket
Socket nextSocket = monServeur.accept();
// Création du Stream pour lire et écrire sur la socket (nextSocket)
BufferedReader reader = new BufferedReader (new InputStreamReader
(nextSocket.getInputStream() ) );
PrintWriter writer = new PrintWriter( new OutputStreamWriter (nextSocket.
getOutputStream() ) );
}
catch (IOException ioe)
{
System.err.println ("I/O error – " + ioe);
}
La méthode setSoTimeout :
Comme son analogue vue supra, cette méthode permet de fixer la période de temporisation d‛une
méthode bloquante. Il s‛agit de accept(). Avec une valeur égale à zéro la période de temporisation
devient infinie.
La méthode toString :
public toString()
Cette méthode renvoie une représentation sous forme de chaîne de caractères de la socket
serveur invoquée (adresse IP du programme distant, son port et le port local).
La méthode close :
Voyons maintenant, comment développer en Java chacun des deux types de serveur présentés dans
le chapitre 1 :
Solution 2 :
import java.net.*;
import java.io.*;
//Attacher la socket au port 13, pour garantir aux clients l'accès au service
daytime
Serveur concurrent :
Les serveurs concurrents traitent plusieurs requêtes en même temps. Ils sont donc implémentés
par des applications muti-thread. Comme vu, au chapitre précédent, le principe est le suivant :
Pour implémenter un serveur concurrent en Java, deux types de thread sont utilisés. Un processus
(thread) primaire et les threads secondaires. Le rôle du thread primaire est : (1) d‛écouter sur le
port correspondant à travers la méthode socket, et, (2) de lancer un thread secondaire, à chaque
fois qu‛un client se connecte. Le lancement du thread secondaire nécessite qu‛une classe de threads
soit déjà définie. Les objets de cette classe sont des threads qui implémentent le service demandé.
Un thread secondaire aura le rôle de réaliser les calculs et les communications nécessaires pour
fournir le service au client en question. Dans l‛exemple suivant nous présentons un code commenté
de la version concurrente du serveur dayTime.
Exemple : serveur dayTime concurent.
import java.net.*;
import java.io.*;
import java.lang.*;
import java.util.*;
public class ServeurDaytimeConc
{
public static final int SERVICE_PORT = 13;
public static void main(String args[])
{
try
{
//Attacher la socket au port 13, pour garantir aux clients l'accès au service
daytime
ServerSocket server = new ServerSocket (SERVICE_PORT);
System.out.println ("le service Daytime a commencé");
//Boucler indéfiniment pour accepter les clients
while (true)
{
//Connexion au prochain client.
Socket nextClient = server.accept();
// Affichage des détailles de la connexion
System.out.println ("Réception d'une requête de" + nextClient.
getInetAddress() + ":" +nextClient.getPort() );
//affectation d'un thread de la classe DaytimeThread (définie en bas)
//et l'initialiser par la socket nextClient
DaytimeThread Dt = new DaytimeThread (nextClient);
// Lancement du thread Dt
Dt.start();
}
}
catch ( Exception exc)
{
System.out.println ("Error - " + exc.toString());
}
}
}
// La classe DaytimeThread
class DaytimeThread extends Thread
{
// La socket sur laquelle s'effectue la communication
Socket incoming;
DaytimeThread (Socket incoming)
{
this. incoming = incoming;
}
// La méthode exécutable implémentée par la classe de thread
public void run()
{
try
{
// Création du Stream pour écrire sur la socket (incoming)
OutputStream out = incoming.getOutputStream();
PrintStream pout = new PrintStream (out);
// Envoyer la date du jour au client
pout.print (new java.util.Date() );
// Effacer les bytes non émis
out.flush();
// Fermeture du stream
out.close();
// Fermeture de la connexion
incoming.close();
}
catch (IOException ioe)
{
System.err.println ("Error " + ioe);
}
}
}
Note : A travers les trois exemples précédents, vous pouvez vous amusez à tester toutes
les méthodes des classes socket et ServerSocket.
[1] "localhost"est le nom assigné à l‛adresse 127.0.0.1 qui représente généralement l‛adresse de la
machine locale.
2. Les classes java.net communes pour les communications orientées
connexion et orientées sans connexion
Dans le réseaux Internet, au niveau application, chaque hôte peut être représenté, soit par une
adresse IP sous la forme de notation décimale à point comme (192.21 22.23), soit, par une
notation textuelle : le nom d ‛ hôte [1] , comme www.google.fr. Un serveur
distribué dit Serveur de noms DNS est utilisé, dans le réseau Internet,
pour la translation des noms d‛hôte en adresses IP et vis vers ça.
Contrairement aux autres classes, celle-ci n‛a pas de constructeur. A la place, elle a des méthodes
qui retournent des objets InetAddress.
Méthodes:
Elle a pour rôle de retourner les différentes adresses IP propres à un hôte dont le nom est
spécifié comme paramètre d'entrée sous la forme de notation décimale à point ou bien sous la
forme d'un nom DNS.
C'est une version spécifique de la précédente, mais cella ne retourne que l'une (aléatoirement)
des adresses IP de l‛hôte. Elle est utilisée pour les hôtes n'ayant qu'une seule carte réseau.
3- La méthode getLocalHost()
Elle permet la comparaison de deux objets. Elle retourne true si les deux objets comparés sont
égaux (la même adresse IP) et false sinon.
5- La méthode getAddress
Elle retourne l'adresse IP brute sous la forme d'une matrice d'octet dans l'ordre des octets du
réseau.
6- La méthode getHostAddress:
Cette méthode a le même rôle que la précédente mais elle retourne une IP sous forme textuelle :
le nom DNS.
import java.net.*;
public class ResolutionAdresse
{
static final String adresseIP="127.0.0.1";
public static void main(String args[])
{
System.out.println ("resolution de l'adresse " + adresseIP);
try
{
InetAddress addr = InetAddress.getByName ( adresseIP);
System.out.println ("Le nom de l'hote correspndant à : "+ addr.
getHostAddress() + " est: "+ addr.getHostName() );
}
catch (UnknownHostException uhe)
{
System.out.println ("Error - incapable de trouver le nom du Hôte " );
}
}
}
[1] La notation textuel nom d‛hôte est apparus pour permettre aux administrateurs,
programmeurs et utilisateurs finaux du réseau de mémoriser facilement les noms des hôtes.
3. Les classes Java.net correspondantes aux communications orientées
sans connexion
Nous allons voir, dans cette section, les différentes classes essentiellement offertes par Java
aux programmes communiquant à distance une communication orientée sans connexion (via UDP).
1) Toutes les informations concernant l‛identification d‛un processus (adresse Ip et port) sont
prise en charge dans les classes socket (Socket et SocketServer) qui établissent le contact et la
communication distante.
Et,
2) Une fois les socket créés et configurées, Les communication sont effectuées à travers les
méthodes d‛entrées/sortie habituelles où les périphériques d‛entrées/ sortie (clavier, écran,
fichier..) sont remplacés par (des objet sockets ou socketServer)
Pour les applications orientées sans connexion, Java consacre toute une classe pour les données
destinées à être communiquées via UDP (sans connexion). C‛est la classe java.net.
DatagramPacket. Un objet de cette classe contiendra en plus des données mises sous forme d‛un
tableau d‛octets, des informations sur l‛adressage du programme
distant , à savoir son adresse IP et son Port. La signification du contenu (Données et
info d‛adressage) d‛un objet DatagramPacket dépend du contexte. En effet, les objets
DatagramPacket sont manipulés soit (1) pour l‛envoi de données vers l‛extérieur, soit, (2) pour la
réception de données venant de l‛extérieur. Dans le premier cas, l‛adresse IP et le port
concernent le programme distant qui va recevoir les données et dans le
deuxième cas, ces informations concernent le programme distant duquel
proviennent ces données. La forme d‛un objet de la classe DatagramPacket est donnée à la
figure suivante:
Les constructeurs :
Les paquets de Datagrammes sont créés et initialisés par des données sous la forme de matrices
(tableaux) d'octets. Et selon que le programme veut envoyer des données ou en recevoir dans sa
communication sans connexion, il utilisera le premier ou le deuxième constructeur de cette classe.
public DatagramPacket ( byte[] Ibuf, int Ilength, InetAddress Iaddr, int port )
Le premier paramètre de ce constructeur indique le tampon à partir duquel doivent être envoyées
les données. Le deuxième indique le nombre d'octets en paquets à envoyer, les deux autres
paramètres permettent lors de l'envoi ultérieur de ce paquet d'identifier le programme cible en
fournissant le couple (adresse IP, numéro de port).
Remarque : Le type des données à encapsuler dans un DatagramPacket devant être le type Byte
[], Java offre pour tous les autre types des méthodes pour la conversion au type Byte[].Par
exemple pour envoyer des données de type string
Exemple :
Les méthodes :
Ces deux méthodes permettent de manipuler l'adresse IP d‛un datagramPacket. L‛une (la
première) sert à récupérer et l‛autre à positionner (c.à.d donner une nouvelle valeur à) l'adresse
IP à laquelle, les données en paquet, doivent être envoyées (si le datagrapPacket est utilisé pour
l‛émission) ou depuis laquelle elles étaient envoyées (si le datagramPacket est utilisé pour
l‛émission).
La première méthode sert à retourner la longueur en octets des données stockées dans le
DatagramPacket (cette longueur peut être inférieure à la taille du tampon de données du
DatagramPacket) et la deuxième permet de fixer cette longueur pour les paquets destinés à
l'envoi.
Les constructeurs :
Ce constructeur permet la création de socket capable de se connecter sur n'importe quel port
local disponible.
Les objets créés par ce constructeur sont des sockets datagramme qui seront attaché sur le port
spécifique indiqué par son paramètre d'entrée
En plus du numéro de port, ce constructeur permet d'indiquer pour les objets créés l'adresse IP
sur laquelle ils seront attachés. Ce dernier constructeur est utilisé lorsque l‛on dispose de
plusieurs adresses IP pour le même hôte (plusieurs cartes réseau par exemple).
NB : Notez que pour pouvoir communiquer à travers UDP : Pour chaque message à communiquer le
programme qui veut le faire doit : (1) spécifier le destinataire (pour que le protocole puisse lui
délivrer les données) et peut être amené à : (2) s‛identifier lui-même en s‛attachant au port sur
lequel il veut recevoir les données et l‛adresse IP s‛il y en a plusieurs (cas d‛un serveur par
exemple). La première tâche est faite via la classe DatagramPacket (nous avons vu en haut que
les informations d‛adressage dans un Datagrampacket concernent toujours le programme distant).
La deuxième tâche est réalisée à travers la classe DatagramSocket.
Les méthodes :
La première méthode récupère l'adresse IP sur laquelle est attachée la socket invoquée et la
deuxième permet d'en récupérer le port.
Sachant que la méthode receive() est bloquante la classe java.net.DatagramSocket offre ces
méthodes permettant l'une de fixer (via son paramètre) et l'autre de retourner la durée (en
milliseconde)de blocage de la méthode receive(), en attente des données.
NB : l‛utilisation du mot connexion (connect) pour nommer cette méthode signifie attachement et
non pas connexion au sens propre du terme.
3.3 Comment établir une communication orientée sans connexion entre deux
programmes ?
R1 : Pour qu‛un programme puisse accéder aux données qui lui sont envoyé, par l‛interlocuteur
distant, il doit d‛abord attacher une socket à un port local en utilisant un constructeur de
DatagramSocket. Il doit aussi, créer un objet DatagramPacket D qui va servir de récipient pour
les données à recevoir. Une fois ces tâches faites, il appelle la méthode DatagramSocket.receive
avec comme paramètre le DatagramPacket D. Cette méthode remplira les différents champs
de D. Le champ data par les données reçues, les champs addresse
IP et port par les valeurs correspondantes à l‛émetteur distant. Le code
commenté suivant illustre un tel comportement. Il s‛agit d‛un programme qui reçoit (infiniment)
des données et les affiche ainsi que leur origine.
import java.awt.*;
import java.net.*;
public class ReceptionSC
{
public static void main(String args[])
{
// Créer un tampon pour la réception
byte[] buffer = new byte[1024];
// Créer un DatagramPacket pour la réception
DatagramPacket D = new DatagramPacket(buffer, buffer.length);
// Créer une DatagraamSocket pour écouter et recevoir les données sur le port 1500
try
{
DatagramSocket socket = new DatagramSocket(1500);
// Boucler infiniment pour recevoir des données
while(true)
{
// Attendre un nouveau packet
try
{
System.out.println("Je suis en attente de reception sur le port "+socket.
getLocalPort());
socket.receive(D);
}
catch(Exception exc)
{
System.out.println("Error! - " + exc.toString());
}
// Extraire les données du Datgrampacket D
String ChaineReçue = new String(buffer, 0, 0,D.getLength());
// Récupérer l'origine du packet
InetAddress OrigineAdresse = D. getAddress();
int port=D.getPort();
// Afficher la chaîne reçue et son origine
System.out.println("J'ai reçus " +ChaineReçue+" de la part de "+
OrigineAdresse.getHostAddress() +" ;" +port);
}
}
catch(Exception exc)
{
System.out.println("Error! - " + exc.toString());
}
}
}
Code 5 : Programme de réception orienté sans connexion (ReceptionSC.java)
R2 : Pour qu‛un programme puisse envoyer des données dans le mode sans connexion, il doit créer
un DatagramPacket D, et positionner ces différents champs. Cela signifie qu‛il doit affecter les
données à envoyer au champ Data, et l‛adresse IP et le port du programme destinataire aux
champs (Ip address, port) de D. Une fois le DatagramPacket D prêt à l‛émission, le programme
doit créer une socket en utilisant un constructeur de DatagramSocket. Et c‛est via la méthode
DatagramSocket.send() avec comme paramètre le Datgrampacket D, que l‛émission est réalisée.
Le code suivant illustre un tel comportement. Il s‛agit d‛un programme qui envoi des salutations
("Bonne année 2007") à un programme sur l‛hôte : HoteDestination dont
le numéro de port est 1500.
import java.net.*;
import java.io.*;
public class EmissionSC
{
// L'adresse Ip de l'hôte serveur.
//Ici, nous avons choisis le même hôte du client pour faciliter le test sur machine isolée
public static final String HoteDistination="127.0.0.1";
public static void main (String args[])
{
try
{
// Préparation du message à envoyer et sa conversion au format byte[]
int année = 2007;
String message= " Bonne année"+année;
// Conversion
int Longueurmessage = message.length();
byte[] messageFinale = new byte[Longueurmessage];
messageFinale = message.getBytes();
// Création d'un datagramPacket contenant notre message
DatagramPacket packet = new DatagramPacket(messageFinale, Longueurmessage );
// Récupération de l'objet InetAddress correspondent à l'hôte destination (ici l'hôte
locale)
InetAddress adresseDistante = InetAddress.getByName(HoteDistination);
// Positionnement des champs adresse et port du DatagramPacket
packet.setAddress (adresseDistante);
packet.setPort (1500);
// Création d'une socket datagram attachée à n'import quel port disponible
DatagramSocket socket = new DatagramSocket();
// Affichage du port affecté à notre socket par l'implémentation
System.out.println ("vous êtes attaché au port local " + socket.getLocalPort());
// Emission du datagramPacket
socket.send (packet);
System.out.println ("le message <<Bonne année 2007>> est émis.");
}
catch (IOException ioe)
{
System.err.println ("Error - " + ioe);
}
}
}
Echo est, pratiquement, un service de diagnostique basé sur UDP qui opère de la manière suivante
(RFC 862) :
Q : En se basant sur les deux exemples précédents, développez en java une version simplifiée de
ce service (codes client et serveur).
Indices :
Le serveur Echo boucle indéfiniment pour servir les clients successivement. Dans chaque itération
il accompli les tâches suivantes :
Solution
import java.net.*;
import java.io.*;
public class ServeurEcho
{
// Définition du port UDP auquel le service est attaché
public static final int SERVICE_PORT = 2007;
// Prendre une taille assez large, pour le tampon, qui suffira normalement pour
n'importe quel client
public static final int BUFTAILLE = 4096;
// Définition de la socket qui sera utilisée pour l'émission et la réception
private DatagramSocket socket;
public ServeurEcho ()
{
try
{
// Attachement de la socket à un port UDP pour écouter les données en entrée
socket = new DatagramSocket( SERVICE_PORT );
System.out.println ("Le serveur est actif sur le port " +socket.getLocalPort() );
}
catch (Exception e)
{
System.err.println ("Unable to bind port");
}
}
public void serviceClients()
{
// Création d'un tampon assez large pour les paquets de données en entrée.
byte[] buffer = new byte[BUFTAILLE];
for (;;)
{
try
{
//Créer un DatagramPacket pour la lecture des paquets de données en entrée
DatagramPacket packet = new DatagramPacket (buffer, BUFTAILLE);
// Réception des paquets de données en entrée
System.out.println ("Le serveur est en attente de réception de données sur
le port : "+socket.getLocalPort() );
socket.receive(packet);
// Extraire les données du Datgrampacket Packet
String MessageReçu = new String ( buffer, 0, 0, packet.getLength());
System.out.println ("Un paquet dont le contenu est : "+ MessageReçu + "
est reçu de la part de: " +packet.getAddress() + ":" + packet.getPort() );
// Renvoi des données reçues vers l'émetteur. Nous utilisons ici le même objet
// datagrampacket puisque l'adresse et le port distant sont déjà bien positionnée
// et aussi les données à retourner qui sont les même pour le service Echo
socket.send(packet);
}
catch (IOException ioe)
{
System.err.println ("Error : " + ioe);
}
}
}
public static void main(String args[])
{
ServeurEcho serveur = new ServeurEcho();
serveur.serviceClients();
}
}
import java.net.*;
import java.io.*;
public class EchoClient
{
// Le port auquel le service à demander est attaché
public static final int SERVICE_PORT = 2007;
// L'adresse Ip de l'hôte serveur.
//Ici, nous avons choisis le même hôte du client pour faciliter le test sur
machine isolée
public static final String HoteServeur="127.0.0.1";
// La taille maximale de paquet de donnée
public static final int BUFSIZE = 256;
public static void main(String args[])
{
// Récupérer l'objet InetAddress correspondent au nom de l'hôte serveur
InetAddress addr = null;
try
{
addr = InetAddress.getByName(HoteServeur);
}
catch (UnknownHostException uhe)
{
System.err.println ("impossible de trouver le nom de l‛hôte ");
return;
}
try
{
// Création d'une socket datagram attachée à n'import quel port disponible
DatagramSocket socket = new DatagramSocket();
// Fixer le temps d'attente en lecture à deux seconds en positionnant la
valeur de //Timeout
socket.setSoTimeout (2 * 1000);
BufferedReader in = new BufferedReader (new InputStreamReader
(System.in));
String line;
System.out.print ("vous pouvez commencer le test du service Echo
sur le poste" +HoteServeur+": ");
while(true)
{
line="";
try
{
line = in.readLine();
}
catch (IOException e)
{
System.err.println(e.getMessage());
}
// Préparer le message à l'envoi en le translatant au format byte[]
char[] TableauC = line.toCharArray();
byte[] TamponEmi= new byte[TableauC.length];
for (int offset = 0; offset < TableauC.length ; offset++)
{
TamponEmi[offset] = (byte) TableauC [offset];
}
// Création du DatagramPacket à envoyer au serveur
DatagramPacket PacketEmi = new DatagramPacket(TamponEmi,
TableauC.length, addr, SERVICE_PORT);
System.out.println ("Envoi du message à " + HoteServeur);
// Envoi du DatagramPacket i
socket.send (PacketEmi);
System.out.print ("En attente du retour.... ");
// Création d'un DatagramPacket pour la réception de l'écho
byte[] TamponRec= new byte[BUFSIZE];
DatagramPacket PacketRec = new DatagramPacket(TamponRec,
BUFSIZE);
// Declaration d'un drapeau timeout pour la gestion collective de toutes
// les exceptions possibles durent l'attente de réception des paquets
boolean timeout = false;
try
{
socket.receive (PacketRec);
}
catch (InterruptedIOException ioe)
{
timeout = true;
}
if (!timeout) // pas d'erreurs
{
System.out.println ("écho reçu");
// Extraire les données du Datgrampacket receivePacket
String MessageReçu = new String (TamponRec, 0, 0, PacketRec.
getLength());
// Afficher le message reçu
System.out.println(" Le serveur à retourné: " +
MessageReçu);
}
else // erreur
{
System.out.println ("massage perdu !");
}
}
}
catch (IOException ioe)
{
System.err.println ("Socket error " + ioe);
}
}
}
Code 8 : Client Echo orienté sans connexion (EchoClient.java)