Blue Flower

Chercher

client et serveur sur différents serveurs

Utilisation des Sockets

Le programme suivant connecte un flot d'entrée à une ressource Web spécifiée par son URL, transforme ce flot d'octets en un flot de caractères et le place dans un tampon ; les lignes successivement lues sur ce flot d'entrée sont copiées sur la sortie standard de l'application (jusqu'à ce que readLine() retourne null).

  • la création et l'utilisation d'URL en Java (java.net.URL URL)
  • l'utilisation de openStream (java.net.URL.openStream())

Premier Programme

 import java.net.URL;
import java.net.MalformedURLException;
import java.io.*;
class URLReader {
  public static void main(String[] args) 
    throws MalformedURLException, IOException {
    URL url = new URL("http://www.singaomara.com/");
    BufferedReader in = 
      new BufferedReader(
        new InputStreamReader(
          url.openStream()));
    String ligne;
    while ((ligne = in.readLine()) != null)
      System.out.println(ligne);  
    in.close();
  }
}

deuxième programme

Utilisation des classes de java.net

Accèder à des ressources sur le World Wide Web, ou plus généralement, sur l'Internet, s'intègre naturellement dans le modèle des flots, i.e la manipulation des caractères et des flux de caractères .Cela conduit donc à travailler avec des classes qui sont définies pour gérer les octets (bytes) ou des flux de caractères. Avec les exemples qui suivent on va étuier une application qui permet la connexion à un service Internet.

Le programme suivant connecte un flot d'entrée à une ressource Web spécifiée par son URL, transforme ce flot d'octets en un flot de caractères et le place dans un tampon (buffer); les lignes successivement lues sur ce flot d'entrée sont copiées sur la sortie standard de l'application (jusqu'à ce que readLine() retourne null).

  • On a besoin donc d'une instance de la classe URL (java.net.URL URL)
  • On fera appel à la méthode openStream (java.net.URL.openStream()); elle permet d'ouvrir un flux d'octets en entrée

Premier Programme

import java.net.URL;
import java.net.MalformedURLException;
import java.io.*;
class URLDeLecture {
  public static void main(String[] args) 
    throws MalformedURLException, IOException {
    URL url = new URL("http://www.singaomara.com/tutorial/montext.txt");
    BufferedReader in = 
      new BufferedReader(
        new InputStreamReader(
          url.openStream()));
    String ligne;
    while ((ligne = in.readLine()) != null)
      System.out.println(ligne);  
    in.close();
  }
}

Dans cette classe on a l'instance de la classe URL qui servira pour:
Déclarer et initialiser la classe url comme suit;
URL url=new URL("http://www.singaomara.com/tutorial/montext.txt");
La méthode url.openStream() retourne une instance de la classe InputStream qui servira de paramètre à une instance de la classe InputStreamReader au moment de son initialisation; La classe BufferedReader va utiliser pour son initilisation ce que retourne new InputStreamReader().
Si on recapitule on a :

 URL url = new URL("http://www.singaomara.com/tutorial/montext.txt");
 BufferedReader in = 
      new BufferedReader(
        new InputStreamReader(
          url.openStream()));
 

et c'est là l'essentiel du programme. La boucle while sert à la saisie du flux d'entrée .

deuxième programme

Pour récupérer des données à partir d'une url, la classe URL fournit les méthodes openConnection, openStream et getContent. Pour bien comprendre leur fonctionnement il faut bien savoir ce qu'elles retournent dès qu'on les invoque. Considérons la méthode openConnection et voyons sa déclaration dans l'API java :
public URLConnection openConnection ()throws IOException{// ici on a le corps de la méthode}
On voit bien qu'elle retourne une instance de la classe URLConection qui représente une connexion vers l'objet désigné par l'url. Ceci sera expliqué prochainement dans le chapitre URLConnection.

En ce qui concerne la méthode getContent () on voit bien qu'elle retourne une instance de la classe Object qui est en faite le contenu de l'url.
 public final Object getContent () throws IOException {// ici on a le corps de la méthode}
Retourne le contenu de l'url. C'est un raccourci pour openConnection().getContent()

La troisième méthode qu'on a déjà vu d'ailleurs, établit la communication en ouvrant un InputStream cela est équivalent à l'utisation de openConnection().openStream() à la seule différence que si on utilise openConnection on a pense utiliser d'autres fonctionnalités pour gérer l'URL
 public final InputStream openStream () throws IOException {// ici on a le corps de la méthode}
L'exemple ci-dessus est encore une illustration d'une utilisation de URL; l'url qu'on aura à traiter sera saisie au clavier au moment de lancer le Programme.

   
import java.io.*;
import java.net.*;
   public class OpenURL {
      public static void main(String[] args) {
         BufferedReader in  = null;
         try {
            if (args.length != 1) {
               System.out.println("usage: java OpenURL <URL>");
               System.exit(0);
            }
            URL url = new URL(args[0]);
            in = new BufferedReader(new InputStreamReader(url.openStream()));
            String s;
            while ( (s=in.readLine()) != null) 
				System.out.println(s);
         }
            catch (IOException e) {System.out.println("Erreur1");}
            catch (Exception e) {System.out.println("Erreur2");}
            finally {
               try { if (in != null) in.close();  }
                  catch (Exception e) {System.out.println("Erreur3");}
            }
      }
   }

Exemple sur les Sockets

Le programme suivant connecte un flot d'entrée à une ressource Web spécifiée par son URL, transforme ce flot d'octets en un flot de caractères et le place dans un tampon (buffer); les lignes successivement lues sur ce flot d'entrée sont copiées sur la sortie standard de l'application (jusqu'à ce quereadLine() retourne null).

  • On a besoin donc d'une instance de la classe URL (java.net.URL URL)
  • On fera appel à la méthode openStream (java.net.URL.openStream()); elle permet d'ouvrir un flux d'octets en entrée

Premier Programme

import java.net.URL;
import java.net.MalformedURLException;
import java.io.*;
class URLDeLecture {
  public static void main(String[] args) 
    throws MalformedURLException, IOException {
    URL url = new URL("http://www.singaomara.com/tutorial/montext.txt");
    BufferedReader in = 
      new BufferedReader(
        new InputStreamReader(
          url.openStream()));
    String ligne;
    while ((ligne = in.readLine()) != null)
      System.out.println(ligne);  
    in.close();
  }
}

Dans cette classe on a l'instance de la classe URL qui servira pour:
Déclarer et initialiser la classe url comme suit;
URL url=new URL("http://www.singaomara.com/tutorial/montext.txt");
La méthode url.openStream() retourne une instance de la classe InputStream qui servira de paramètre à une instance de la classe InputStreamReader au moment de son initialisation; La classe BufferedReader va utiliser pour son initilisation ce que retourne new InputStreamReader().
Si on recapitule on a :

 URL url = new URL("http://www.singaomara.com/tutorial/montext.txt");
 BufferedReader in = 
      new BufferedReader(
        new InputStreamReader(
          url.openStream()));

et c'est là l'essentiel du programme. La boucle while sert à la saisie du flux d'entrée .

deuxième programme

Pour récupérer des données à partir d'une url, la classe URL fournit les méthodes openConnection, openStream et getContent. Pour bien comprendre leur fonctionnement il faut bien savoir ce qu'elles retournent dès qu'on les invoque. Considérons la méthode openConnection et voyons sa déclaration dans l'API java :
public URLConnection openConnection ()throws IOException{// ici on a le corps de la méthode}
On voit bien qu'elle retourne une instance de la classe URLConection qui représente une connexion vers l'objet désigné par l'url. Ceci sera expliqué prochainement dans le chapitre URLConnection.

En ce qui concerne la méthode getContent () on voit bien qu'elle retourne une instance de la classe Object qui est en faite le contenu de l'url.
 public final Object getContent () throws IOException {// ici on a le corps de la méthode}
Retourne le contenu de l'url. C'est un raccourci pour openConnection().getContent()

La troisième méthode qu'on a déjà vu d'ailleurs, établit la communication en ouvrant un InputStream cela est équivalent à l'utisation de openConnection().openStream() à la seule différence que si on utilise openConnection on a pense utiliser d'autres fonctionnalités pour gérer l'URL
 public final InputStream openStream () throws IOException {// ici on a le corps de la méthode}
L'exemple ci-dessus est encore une illustration d'une utilisation de URL; l'url qu'on aura à traiter sera saisie au clavier au moment de lancer le Programme.

   import java.io.*;
   import java.net.*;
   public class OpenURL {
      public static void main(String[] args) {
         BufferedReader in  = null;
         try {
            if (args.length != 1) {
               System.out.println("usage: java OpenURL <URL>");
               System.exit(0);
            }
            URL url = new URL(args[0]);
            in = new BufferedReader(new InputStreamReader(url.openStream()));
            String s;
            while ( (s=in.readLine()) != null) 
				System.out.println(s);
         }
            catch (IOException e) {System.out.println("Erreur1");}
            catch (Exception e) {System.out.println("Erreur2");}
            finally {
               try { if (in != null) in.close();  }
                  catch (Exception e) {System.out.println("Erreur3");}
            }
      }
   }

La classe java.net.Socket et de java.net.ServerSocket

Le programme suivant se connecte à un serveur d'heure qui tourne en permanence et récupère l'heure. Ici on se sert des sockets pour établir la connexion .

Programme client : CliHeure.java

l'exemple d'un programme qui récupère l'heure sur un serveur web et qui l'affiche à l'écran:

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;

 public CliHeure(String adresse, int port) {
  portServeur=port;
  adresseServeur=adresse;
  addWindowListener(new Fermeture()); 
  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=new Thread(this);
  processus.start();
 }
    
 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;
  }
 } 

 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());
  } 
 }

 public void disconnect() {
  try {
   sk.close();
  } catch (IOException e) {
  }
 } 

 public void actionPerformed(ActionEvent e) {
  if (e.getActionCommand().equals("Heure")) versServeur.println("h");
 }
 
 class Fermeture extends WindowAdapter {
  /**
   * Gestion de l'événement Cas de fermeture
   */
  public void windowClosing(WindowEvent e) {
   versServeur.println("");
   disconnect();
   System.exit(0);
  }
 }
 public static void main(String args[]) {
  System.out.println("Chargement en cours...");
  CliHeure cli=new CliHeure("localhost",1234);
  cli.setTitle("Heure");
  cli.setVisible(true);
 }
}

Analysons le code

On veut se connecter au serveur d'heure et récuperer l'heure exacte . Dans ce cas on a besoin de Variables permettant d'établir la connection et de dialoguer avec le serveur. Pour établir la connexion on déclare la variable sk de type Socket ( voir la ligne Socket sk ; ) ; mais pour établir la connexion il faut connaître : l'adresse ( le nom du serveur qui propose le service et le numéro du port sur lequel le service est disponible; cela nous emmène à déclarer les varibles:

 int portServeur; <--- port de communication
 String adresseServeur; <--- nom ou adresse de la machine serveur
 Thread processus=null; <--- processus permet de parallèliser les demandes 
 

Ensuite, dans le constructeur on initialise les variables et on lance le processus via le Thread processus . La gestion de la communnication et l'échange d'informations sont gérées par la méthode run() (n'oublions pas que notre classe implements une interface Runnable).
On tente donc de se connecter au serveur spécifié via le port adéquat.
On voit bien qu'on a ainsi demandé un service en donnant toutes les précisions permettant d'être bien servi. Construisons metenant le serveur (il doit être lancé avant tout programme client).

deuxième programme serveur : ServHeure.java

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

public class ServHeure {

 static int port;

 public static void main(String args[]) {
  ServerSocket serveur;
  //définition du port
  try {
   port=Integer.parseInt(args[0]);
  } catch (Exception e) {
   port=1234;  //valeur par défaut
  }
  //installation
  try {
   serveur=new ServerSocket(port);
   System.out.println("Serveur d'heures OK.");
   while (true) {
    //création de nouvelles connexions
    Socket s=serveur.accept();
    new MaConnexion(s);
   } 
  } catch (IOException e) {
   System.out.println("Erreur à la creation d'un objet Socket : "+e.getMessage());
   System.exit(1);
  }
 }
}

/**
 * La classe MaConnexion crée un processus de dialogue avec le client
 */
class MaConnexion implements Runnable {
 Socket client;               //liaison avec client
 BufferedReader depuisClient; //réception de requête
 PrintWriter versClient;      //envoi des réponses
 
 //Constructeur
 public MaConnexion(Socket client) {
  this.client=client;
  try {
   // création des flots de/vers le client
   depuisClient=new BufferedReader(new InputStreamReader(client.getInputStream())); 
   versClient=new PrintWriter(new OutputStreamWriter(client.getOutputStream()),true);
   // message d'accueil
   versClient.println("Bienvenue sur le serveur d'heure.");
   versClient.println("Entrez h pour obtenir l'heure.");
   versClient.println("Envoyez une chaîne vide pour fermer la connexion.");
  } catch (IOException e) {
   try { 
   client.close(); 
   } catch (IOException ee) {}
  }
  //mise en route du processus par appel de la méthode run
  new Thread(this).start();
 }

 //processus de dialogue
 public void run() {
  boolean fini=false;
  try {
   String lue;  //la requête
   String rep;  //la réponse
   while (!fini) {
    lue=depuisClient.readLine();
    if (lue==null) fini=true;
    else if (!lue.equals("h")) fini=true;
    else {
     //on envoie l'heure
     Calendar cal=Calendar.getInstance();
     rep="Il est "+cal.get(Calendar.HOUR)+"h"
        +cal.get(Calendar.MINUTE)+"mn"+cal.get(Calendar.SECOND)+"s.";
     versClient.println(rep);
    }
   }
  } catch (IOException e) {
   System.out.println("Exception entrée/sortie : "+e.getMessage());
  } 
  //fermeture de la connexion
  stop();
 }
    
 public void stop() {
  try {
   versClient.println("Au revoir !");
   client.close();
  } catch (IOException e) {
   System.out.println("Exception à la fermeture d'une connexion : "+e);
  }
 }
    
}

Analysons le code

Ici , comme dans le premier programme , on doit définir un certain nombre de variables permettant, de présenter le service que propose le serveur, d'une part et d'autre part des variables permettant l'échange d'informations avec les éventuels clients.

static int port; <---- le port 
.....
ServeurSocket serveur = new ServerSocket(port);              <---- le serveur 
.......
Socket client;              <---- liaison avec client 
 BufferedReader depuisClient; <---- réception de requête
 PrintWriter versClient;      <---- envoi des réponses
 La classe interne Maconnexion Runnable va gérer les connexions à travers la méthode run()