TP3 - Nicolas Baudru

Transcription

TP3 - Nicolas Baudru
Java - TP3
Nicolas Baudru, Carine Guivier-Curien, Laurent Vallet
Année 2008-2009
Le but de ce TD est d'écrire une application client/serveur de type msn :
1. Des clients se connectent à un serveur
2. Un client envoie un message au serveur
3. le serveur distribue le message à tous les clients.
Nous nous focaliserons ici uniquement sur les aspects réseaux. La conception de l'IHM (Interface
Homme-Machine) ne fait pas partie de ce TP. Par conséquent, elle vous est donnée clé en main .
Affiche les messages transmis
par le Client et retourne au client
le message à envoyer
IHM.class
Demande à l'IHM
d'afficher les messages
reçus et transmet les
messages de l'IHM
Client.class
au serveur
Serveur.class
Recoit un message
d'un client puis le
transmet à tous les clients
Client.class
Client.class
1
Ce TP se décompose en trois étapes. Dans un premier temps, vous allez aprendre à utiliser
l'IHM qui vous est donnée. Puis vous écrirez la partie client de l'application. Le client se connecte
au serveur, transmet et reçoit des messages et interagit avec l'IHM. A cette étape, vous utiliserez
l'IHM vu à l'étape 1 ainsi qu'un serveur clé en main qui vous sera fournit pour pouvoir tester
votre client. Enn, si vous allez au bout de ce TP, vous écrirez vous-même la partie serveur.
Exercice 1 (prise en main de l'IHM)
La classe IHM est disponible à l'adresse
http ://nicolas.baudru.perso.esil.univmed.fr/Enseignement/enseignement.html
Sa structure est la suivante :
public class IHM implements ActionListener {
public IHM () { // Initialise l ' IHM }
public void go () {
// Une interface graphique type msn s ' affiche à l ' écran
}
synchronized public String getNextMessageToSend () {
// Affiche dans un terminal le message tapé dans l ' IHM
// puis retourne ce message
}
public void writeMessage ( String mess ) {
// écrit dans la fenêtre de discussion
// ET dans le terminal le chaîne de caracères
}
} // fin class IHM
mess
Remarque : la méthode getMessageToSend() est bloquante. Cela signie que le thread invoquant
cette méthode reste bloqué sur cette méthode (son exécution est suspendue) jusqu'à ce que
l'utilisateur presse la touche envoi de l'IHM.
1. Ecrire une classe TestIHM1 qui successivement ache dans un terminal le message écrit dans l'IHM,
puis demande à l'utilisateur de taper une phrase dans le terminal,
et enn, ache cette dernière phrase dans l'IHM.
2. Ecrire une classe TestIHM2 qui de manière concurrente ache dans un terminal tous les messages écrits dans l'IHM par l'utilisateur
ache dans l'IHM tous les messages écrits par l'utilisateur dans le terminal.
Indication : l'utilisation de Threads est nécessaire.
Exercice 2 (coté client)
L'écriture du programme client nécessite de savoir faire trois choses :
2
comment établir une connexion avec le serveur
comment envoyer des messages au serveur
comment recevoir des messages du serveur
Établir une connexion en Java :
Pour établir une connexion à un serveur, il faut connaître le serveur , i.e. son adresse IP et
son numéro de port TCP. Autrement dit il faut connaître la s ocket du serveur (c-à-d le couple
(IP,port)). En Java c'est la seule information nécessaire à l'établissement d'une connexion. Tout le
reste se fait automatiquement au travers de la classe Socket du package java.net :
Socket maSocket = new Socket ( " 192.164.2.21 " , 5000);
Cette simple ligne crée une socket du coté client nommée maSocket puis établie une connexion entre
maSocket et la socket du serveur ("192.164.2.21", 5000).
Recevoir des données sur une socket :
Toutes les classes et méthodes qui suivent se trouvent dans le package java.io.* qui est donc à
inclure dans votre programme. Pour recevoir des données, il sut de demander à la socket de nous
donner ce qu'elle a reçu :
monFlotBasNiveau = maSocket . getInputStream ();
Cette méthode renvoie un objet de type InputStream permettant de récupérer un ot d'E/S de bas
niveau (un truc du type 010011...). An de récupérer un ot plus "sympa", à base de caractères,
on va chaîner un objet de type InputStreamReader à ce ot de bas niveau :
InputStreamReader monFlotDeCaracteres =
new InputStreamReader ( monFlotBasNiveau );
L'objet monFlotDeCaracteres permet de récupérer le ot de caractères correspondant au ot de bas
niveau (cela se fait caractère par caractère à l'aide de la méthode read()). An d'utiliser facilement
ce ot de caractères et pour plus d'ecacité, nous pouvons le "bueriser" :
BufferedReader monBuffer =
new BufferedReader ( monFlotDeCaractere )
Nous pouvons alors récupérer les messages lignes par lignes par exemple :
String monMessage = monBuffer . readLine ();
Pour fermer l'ensemble des ots de données, il sut de taper
monBuffer . close ();
Envoyer des données sur une socket :
Plusieurs méthodes sont possibles. Par exemple nous pouvons chaîner un BueredWritter à un
OutputStreamWritter, lui même chaîné au ot de bas niveau de sortie du socket :
BufferedWritter monBuffer = new BufferedWritter (
new OutputStreamWritter ( monSocket . getOutputStream ()));
3
Pour écrire sur la socket :
monBuffer . write ( " blabla " );
Les messages écrits seront envoyés à la socket une fois le buer plein (on peut aussi utiliser la
méthode ush() pour forcer le buer à ce vider) .
Plus simplement, on peut aussi utiliser PrintWritter qui se chargera de transformer une chaîne
de caractères en ot de bas niveau. Cet objet doit être chaîné au ot de bas niveau de la socket :
PrintWritter maChaine =
new PrintWritter ( monSocket . getOutputStream ());
Et pour écrire sur la socket :
maChaine . println ( " blabla " );
// suivit de
maChaine . flush (); // pour envoyer les données .
Pour fermer l'ensemble des ots de données, il sut de taper
maChaine . close ();
Questions :
Pour pouvoir tester votre programme client, vous aurez besoin d'un serveur test. Celui-ci est
disponible à l'adresse
http ://nicolas.baudru.perso.esil.univmed.fr/Enseignement/enseignement.html
Pour le faire fonctionner, vous devez télécharger le chier Serveur.zip, le décompresser, puis taper java Serveur dans un terminal (à partir du répertoire décompressé). Le port par défaut utilisé par
le serveur est le port 5000. Si ce port n'est pas disponible ou ne fonctionne pas sur votre machine,
vous pouvez choisir un autre port pour le serveur en le rajoutant simplement en argument. Par
exemple java Serveur 12321 démarre le serveur sur le port 12321.
1. Écrire la classe ClientSimplie décrite ci-dessous. Cette classe est un petit programme qui
permet de se connecter au serveur (en lui précisant l'adresse IP et le port du serveur), de lui
envoyer un message et enn de recevoir un message du serveur.
2. Lorsque la classe compile, tester-la en utilisant le serveur test. Pour cela lancer le programme
Serveur dans un premier terminal. Dans un autre terminal, lancer votre programme ClientSimplie. Vérier que vous recevez bien le message envoyé.
3. Pousser le test un peu plus loin en exécutant de nouveau le programme ClientSimplie dans
deux nouveaux terminaux simultanément. Que se passe-t-il ?
4. Écrire une nouvelle classe ClientSansIHM basée sur le modèle de la classe ClientSinplie mais
utilisant deux threads dans son main() :
l'un permet d'envoyer en boucle des messages au serveur (les messages à envoyer sont tapés
par l'utilisateur dans le terminal)
l'autre permet de receptionner tous les messages en provenance du serveur.
5. Tester de nouveau votre classe avec le serveur test.
6. Enn, écriver la classe Client nale en intégrant l'IHM à la classe ClientSansIHM.
4
import java . io .*;
import java . net .*;
import java . util .*;
public class ClientSimplifie {
BufferedReader lecture ; // pour le flot d ' entrée venant du serveur
PrintWriter ecriture ; // pour le flot de sortie vers le serveur
Socket sock ;
// le socket client
public ClientSimplifie () {
// établie une connexion au serveur par un appel à connexionServeur ()
}
private void connexionServeur ( String adresseIPServeur , portServeur ) {
// créer un objet socket lié au socket serveur et l ' affecte à sock
// puis établie les chaînages de flot nécessaires
// pour l ' envoi et la reception de messages
}
public static void main ( String [] args ) {
// crée un nouveau client
// envoi un seul message au serveur
// puis dans une boucle infini , affiche les messages reçus du serveur
}
} // fin classe ClientSimplifie
Exercice 3 (coté serveur)
Quatre choses à savoir faire :
créer une "socket d'écoute" qui attend une demande de connexion
accepter et établir une connexion avec le client
comment envoyer des messages au client
comment recevoir des messages du client
Créer une socket d'écoute :
Très simple en Java. La ligne suivante crée une socket d'écoute sur un port donné. Cette socket
écoute les requêtes entrantes d'un client qui souhaiterait se connecter.
ServerSocket monSocketEcoute = new ServeurSocket (6345);
Accepter et établir une connexion avec le client :
Socket monSocket = monSocketEcoute . accept ();
Cette ligne crée une nouvelle socket chez le serveur (diérente du socket d'écoute) et établie une
connexion avec le client. La méthode accept() est bloquante, c'est-à-dire que le thread courant
exécutant cette méthode va rester bloqué jusqu'à ce qu'une demande de connexion provenant d'un
client se produise. La méthode accept() va alors créer la nouvelle socket chez le serveur et établir
5
la connexion entre cette nouvelle socket et la socket client (le serveur connaît la socket client car la
demande de connexion d'un client contient toujours la socket de ce client).
Remarques :
Notez bien que la connexion s'eectue sur un port diérent de la socket d'écoute. Cette
dernière peut donc continuer d'attendre d'autres demandes de connexion.
Pour chaque demande de connexion, une nouvelle socket est créée coté serveur. Donc chez
le serveur, un client peut être identié à la socket créée lors de l'acception de la requête de
connexion.
Recevoir et envoyer des données sur la socket :
L'envoi et la réception de données du coté serveur s'eectuent de la même manière que pour le
client. Il sut d'utiliser la socket correspondant à un client donné pour communiquer avec ce client.
Question :
Tenter d'écrire votre propre serveur. Celui-ci ressemble au Client mais doit en plus pouvoir
gérer une liste de clients. Son comportement est des plus simples. Le serveur attend un message
d'un client quelconque puis diuse ce message à l'ensemble des clients.
6

Documents pareils