Un programme client essaie d'établir une connexion à un programme serveur par l'intermédiaire d'un objet de la classe Socket. Il envoie ensuite des requêtes et reçoit des réponses.
On obtient une connexion à un serveur en créant un objet de la classe Socket. Le constructeur utilisé doit fournir en paramètres le nom de l'ordinateur contenant le serveur et le numéro de port du serveur. On pourra par exemple écrire :
Socket sk=new Socket(adresseServeur,numPort);
L'objet Socket obtenu lors de la connexion fournit des flots d'entrée et de sortie grâce aux méthodes getInputStream et getOutputStream. Ceci permet d'obtenir des objets BufferedReader et PrintWriter pour dialoguer avec le serveur par l'intermédiaire de chaines de caractères.
BufferedReader depuisServeur=new BufferedReader( new InputStreamReader(sk.getInputStream())); PrintWriter versServeur=new PrintWriter( new OutputStreamWriter(sk.getOutputStream()),true);
Après avoir obtenu une connexion, le programme client pourra créer un processus d'écoute des messages du serveur. Les requêtes seront envoyées à l'aide d'un bouton, les réponses seront affichées dans un composant.
Ecrivons un programme client pour le serveur d'heure créé précédemment. Celui-ci renvoie l'heure sous la forme d'une chaine de caractères du type "Il est 10h26mn45s." lorsqu'on lui transmet la requête "h".
Le programme client utilisera les variables suivantes :
On obtient le code suivant :
import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; public class CliHeure extends Frame implements Runnable, ActionListener { int portServeur; String adresseServeur; Thread processus=null; Label heure=new Label("Connexion au serveur d'heure"); Socket sk; BufferedReader depuisServeur; PrintWriter versServeur;
Le constructeur récupère le nom d'ordinateur et le numéro de port passés en paramètres, construit l'interface du programme (un Label et un Button), crée le processus d'attente des messages et le lance avec la méthode run qui commencera par établir la connexion. On obtient le code suivant:
public CliHeure(String adresse, int port) { portServeur=port; adresseServeur=adresse; //évènement fermeture addWindowListener(new Fermeture()); //création de l'interface Panel p=new Panel(); p.setBackground(Color.white); add(BorderLayout.CENTER,p); p.setLayout(new GridLayout(2,1)); p.add(heure); heure.setAlignment(Label.CENTER); Panel p1=new Panel(); p.add(p1); Button b=new Button("Heure"); p1.add(b); b.addActionListener(this); pack(); //processus d'attente des messages processus=new Thread(this); processus.start(); }
La connexion et la déconnexion au serveur se feront avec les méthodes connect et disconnect.
La méthode connect crée le Socket de communication et initialise les flots d'entrée et de sortie.
public void connect() { try { sk=new Socket(adresseServeur,portServeur); depuisServeur=new BufferedReader( new InputStreamReader(sk.getInputStream())); versServeur=new PrintWriter( new OutputStreamWriter(sk.getOutputStream()),true); //demander l'heure versServeur.println("h"); } catch (Exception e) { heure.setText(e.toString()); } }
La méthode disconnect se contente de fermer le Socket obtenu lors de la connexion en appelant sa méthode close.
public void disconnect() { try { sk.close(); } catch (IOException e) { } }
La méthode run attendue pour l'implémentation de l'interface Runnable va créer la connexion, puis attendre les messages du serveur. Seuls ceux commençant par "Il est" seront pris en compte et affichés dans le Label heure.
public void run() { boolean fini=false; try { connect(); String ligne; while (!fini) { ligne=depuisServeur.readLine(); if (ligne==null) fini=true; else if (ligne.startsWith("Au revoir")) fini=true; else if (ligne.startsWith("Il est")) heure.setText(ligne); } } catch (IOException e) { heure.setText("Connexion impossible."); } finally { processus=null; } }
Les requêtes sont envoyées lors de l'appui sur le bouton "Heure". Elles se réduisent à la chaine "h". Ceci nous donne la méthode actionPerformed suivante:
public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Heure")) versServeur.println("h"); }
La classe Fermeture dérivée de WindowAdapter gèrera l'évènement fermeture de la fenêtre.
class Fermeture extends WindowAdapter { public void windowClosing(WindowEvent e) { versServeur.println(""); disconnect(); System.exit(0); } }
Il reste à écrire la méthode main qui crée une instance de la fenêtre du programme et l'affiche.
public static void main(String args[]) { System.out.println("Chargement en cours..."); String adr="localhost"; if (args.length>0) adr=args[0]; int p=1234; if (args.length>1) { try { p=Integer.parseInt(args[1]); } catch (Exception e) {p=1234;} } CliHeure cli=new CliHeure(adr,p); cli.setTitle("Heure"); cli.setVisible(true); }
Après avoir lancé le serveur d'heure, on lance le programme obtenu.
A chaque appui sur le bouton "Heure" l'heure est mise à jour.