Page d'accueilFindIt !ContactLa gestion des fichiers et des flux de donnéesLes applications et les applets

La bibliothèque JavaTM 1.0

Table des matièresHierarchie des classes

CJava

 Les accès au réseau

Accès via une URL
L'architecture client-serveur
Accès via les sockets
Accès via les datagrams

 

Ce chapitre décrit le package java.net de Java 1.0 qui rassemble les classes permettant de gérer les accès réseau via une URL ou par les sockets.

Accès via une URL

Les accès au réseau peuvent se faire à plusieurs niveaux en Java.
Le niveau le plus simple permet d'accéder à un fichier sur le réseau grâce à son URL (Uniformed Resource Locator) : Contrairement au chemin d'accès classique à un fichier dont la notation varie d'un système à l'autre (c:\fichier.txt, /usr/unCompte/fichier.txt), une URL permet de désigner un fichier de manière uniforme quelque que soit le système qui héberge ce fichier.
Même si vous ne la connaissiez pas sous ce nom, l'adresse d'un site Internet est une URL : http://www.javasoft.com/index.html, http://www.eteks.com/coursjava/net10.html#AccesURL sont des exemples d'URL.
De quoi est composée une URL ?

Une URL peut représenter un fichier mais aussi de manière plus générale une ressource. Par exemple, une ressource peut être un programme renvoyant une image ou le résultat d'un accès à une base de données. La plupart des programmes auxquels on accède sur un site Internet via une URL utilise le modèle CGI (Common Gateway Interface). Ce standard définit comment appeler un programme et lui transmettre ses paramètres.
Par exemple, http://www.hit-parade.com/hp.asp?site=a15740 est un programme CGI appelé avec la valeur a15740 pour le paramètre site. Ce programme renvoie l'image du site hit-parade.com.

Java permet d'accéder au fichier ou à la ressource représentés par une URL sous forme de flux de données, grâce aux deux classes URL et URLConnection.

La classe java.net.URL

Cette classe final permet de manipuler une URL sous forme d'un objet constant. Les constructeurs de cette classe pouvant éventuellement déclencher une exception de classe MalformedURLException, la création d'une nouvelle instance de classe URL doit être programmée dans un bloc try ... catch. L'objet créé ne garantit pas que le fichier existe mais seulement que l'URL mémorisée par l'objet est correctement formée et que le protocole spécifié est géré par la Machine Virtuelle Java.
Les objets de cette classe sont utilisés pour accéder sous forme de flux de données au fichier correspondant, mais aussi par certaines méthodes de la classe Applet pour obtenir l'URL d'un document HTML, lire une image ou un fichier son.

Constructeurs
public URL (String protocol, String host, int port, String file)
                throws MalformedURLException
public URL (String protocol, String host, String file)
                throws MalformedURLException

Ces constructeurs permettent de créer un objet de classe URL à partir du protocole protocol, l'hôte host, le port port et le chemin d'accès file d'une URL.

public URL (String spec) throws MalformedURLException

Construit une instance de classe URL à partir de la chaîne de caractères spec représentant une URL.

public URL (URL context, String spec) throws MalformedURLException

Construit une instance de classe URL à partir d'une URL existante context et de la chaîne de caractères spec. Si spec décrit entièrement une URL (avec protocole, hôte, fichier,...) , l'URL context est ignorée et l'objet créé correspond à l'URL spec. Sinon, context est utilisé comme base complétée par les informations fournies dans spec, pour construire le nouvel objet de classe URL (spec peut par exemple désigné un fichier dans un sous répertoire différent).

Méthodes
 
public String getProtocol ()
public String getHost ()
public int getPort ()
public String getFile ()
public String getRef ()

Ces méthodes permettent d'interroger le protocole, l'hôte, le port, le chemin d'accès au fichier et la référence mémorisée dans une instance de la classe URL. Si le port n'a pas été précisé en paramètre du constructeur, la valeur -1 est renvoyée.

public boolean sameFile (URL other)

Renvoie true si other désigne la même URL que l'objet sur lequel est invoquée cette méthode. Les références mémorisées par les objets ne sont pas prises en compte pour la comparaison.

public String toExternalForm ()

Renvoie une chaîne de caractères correspondant à l'URL mémorisée par un objet de classe URL.

public final InputStream openStream () throws IOException

Ouvre en lecture la connexion avec une URL, et renvoie une instance de la classe InputStream pour accéder aux données sous forme de flux de données.

public final Object getContent () throws IOException

Renvoie un objet correspondant au contenu du fichier représenté par un objet de classe URL. Par exemple, si le fichier est une image, cette méthode renverra une instance d'une classe dérivée de la classe Image.

public URLConnection openConnection () throws IOException

Ouvre une connexion avec une URL, et renvoie une instance de la classe URLConnection qui permet d'obtenir toute sorte de renseignements (dates, en-tête,...) sur le fichier correspondant à l'URL.

public static synchronized void setURLStreamHandlerFactory
                                       (URLStreamHandlerFactory fac)
                                   throws SecurityException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de création de flux de données pour chacun des protocoles reconnus. Cette méthode static ne peut être appelée qu'une seule fois. Par défaut, la Machine Virtuelle Java reconnaît un certain nombre de protocoles (voir l'exemple qui suit).

public int hashCode ()
public boolean equals (Object obj)
public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer un objet de classe URL à un objet ou renvoyer une chaîne de caractères correspondant à l'URL.

L'application suivante permet de tester si la Machine Virtuelle Java accepte ou non les 4 protocoles les plus communément utilisés : http, ftp, file et mailto. Recopiez-la dans un fichier TestProtocole.java, que vous compilez avec l'instruction javac TestProtocole.java pour ensuite l'exécuter avec java ou Java Runner, grâce à l'instruction java TestProtocole :

import java.net.*;
 
public class TestProtocole
{
  public static void main (String [] args)
  {      
    // Tableau avec 4 URL à tester
    String urlTest [] = {"http://www.eteks.com/index.html",
                         "ftp://www.eteks.com/index.html",
                         "file://C//java/bin/java.exe",
                         "mailto:puybaret@imaginet.fr"};
 
    for (int i = 0; i < urlTest.length; i++)
      try
      {
        // Création d'une URL
        URL url = new URL (urlTest [i]);
        System.out.println ("URL : " + url + " correctement form\u00e9e\n"
                            + " et protocole " + url.getProtocol () + " reconnu.");
      }
      catch (MalformedURLException e)
      { 
        // URL incorrect ou protocole inconnu
        System.out.println ("URL : " + urlTest [i] + " incorrect\n"
                            + " ou protocole non reconnu\n"
                            + "(Exception " + e + ").");
      }
  } 
}
 
Autre exemple

Applets HelloFromNet et BoutonsNavigation.

La classe java.net.URLConnection

Cette classe abstract gère la connexion avec une URL. Une instance d'une classe dérivant de cette classe peut être obtenue grâce à la méthode openConnection () de la classe URL.
Les méthodes de cette classe permettent de créer un flux de données pour lire et/ou d'écrire dans le fichier désigné par une URL, mais aussi d'obtenir toute sorte d'information sur ce fichier (sa date de dernière modification, sa taille, son type,...).

Champs
protected URL url
protected boolean doInput
protected boolean doOutput
protected boolean allowUserInteraction
protected boolean useCaches
protected long ifModifiedSince
protected boolean connected

Ces champs protected sont utilisés par les classes dérivées de la classe URLConnection.

Constructeur
protected URLConnection (URL url)
Méthodes
public URL getURL ()

Renvoie l'URL avec laquelle la connexion est faite.

public InputStream getInputStream () throws IOException
public OutputStream getOutputStream () throws IOException

Ces méthodes renvoient un flux de données en lecture ou en écriture à partir d'une connexion à une URL. Une exception de classe UnknownServiceException (dérivant de la classe IOException) est déclenchée si le protocole interdit l'accès en lecture ou en écriture à cette URL.

public int getContentLength ()

Renvoie la taille du fichier avec lequel la connexion est faite ou 0 si cette taille n'est pas connue.

public String getContentType ()
public String getContentEncoding ()

Renvoie le type du contenu et son codage ou null si ces renseignements ne sont pas connus

public Object getContent () throws IOException

Renvoie un objet correspondant au contenu du fichier.

public long getDate ()
public long getLastModified ()
public long getExpiration ()

Renvoie la date à laquelle le fichier a été envoyé, sa date de dernière modification et sa date d'expiration ou 0 si ces renseignements ne sont pas connus.

public String getHeaderField (String name)
public int getHeaderFieldInt (String name, int default)
public long getHeaderFieldDate (String name, long default)
public String getHeaderFieldKey (int n)
public String getHeaderField (int n)

Ces méthodes renvoient les renseignements correspondant aux clés contenues dans l'entête d'un fichier

public boolean getDoInput ()
public boolean getDoOutput ()
public boolean getUseCaches ()
public boolean getAllowUserInteraction ()

Ces méthodes renvoient true, s'il est possible de lire ou d'écrire sur une connexion, si la connexion utilise le cache ou si elle autorise d'interagir avec l'utilisateur (pour lui demander par exemple un mot de passe). Par défaut, une connexion est ouverte en lecture.

public long getIfModifiedSince ()

Renvoie la durée de validité du fichier sur la connexion est faite.

public String getRequestProperty (String key)

Renvoie la valeur associée à la clé key par lequel une requête est reconnue.

public abstract void connect () throws IOException

Les classes dérivées de la classe URLConnection doivent implémenter cette méthode pour réaliser la connexion avec une URL.

public void setDoInput (boolean doinput)
public void setDoOutput (boolean dooutput)
public void setUseCaches (boolean usecaches)
public void setAllowUserInteraction (boolean allowuserinteraction)
public void setIfModifiedSince (long ifmodifiedsince)
public void setRequestProperty (String key, String value)

Ces méthodes permettent d'autoriser l'accès en lecture ou en écriture à un fichier, l'utilisation du cache,... Elles ne peuvent pas être appelées quand la connexion est déjà ouverte.

public boolean getDefaultUseCaches ()
public void setDefaultUseCaches (boolean defaultusecaches)
public static boolean getDefaultAllowUserInteraction ()
public static void setDefaultAllowUserInteraction
                             (boolean defaultallowuserinteraction)
public static String getDefaultRequestProperty (String key)
public static void setDefaultRequestProperty (String key, String value)
protected static String guessContentTypeFromName (String fname)
protected static String guessContentTypeFromStream (InputStream is)
                             throws IOException
 
public static synchronized void setContentHandlerFactory (ContentHandlerFactory fac) 
                                    throws SecurityException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de création d'objets représentés dans un fichier suivant leur type mime, différent de celui fourni par défaut. Cette méthode static ne peut être appelée qu'une seule fois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant la connexion.

Voici un exemple simple d'applet qui lit le texte contenu dans le fichier accessible à l'URL http://www.eteks.com/classes/hello.txt pour l'afficher à l'écran :

Applet HelloFromNet

et le programme Java correspondant (à copier dans un fichier dénommé HelloFromNet.java et invoqué à partir d'un fichier HTML) :

import java.applet.Applet;
import java.awt.Graphics;
import java.net.*;
import java.io.*;
 
public class HelloFromNet extends Applet
{
  String texteLu;
  
  // Méthode appelée par le système à l'initialisation de l'applet
  public void init ()
  {
    try
    {
      // Création de l'URL http://www.eteks.com/classes/hello.txt
      URL urlFichierHello = new URL ("http",
                                     "www.eteks.com", 
                                     "/classes/hello.txt");
      // Ouverture d'une connexion et récupération d'un flux d'entrée                                     
      URLConnection connexion   = urlFichierHello.openConnection ();
      InputStream   fluxFichier = connexion.getInputStream ();
 
      // Lecture du contenu du flux d'entrée
      byte contenuFichier [ ] = new byte [connexion.getContentLength ()];
      int  octetsLus = fluxFichier.read (contenuFichier);
        
      texteLu = new String (contenuFichier, 0, 0, octetsLus);
 
      // Fermeture de la connexion
      fluxFichier.close ();
    }
    catch (Exception e)
    { 
      texteLu = "Probleme...";
    }
  }
 
  // Méthode appelée par le système pour mettre à jour le dessin de l'applet
  public void paint (Graphics gc)
  {
    if (texteLu != null)
      // Affichage du texte lu
      gc.drawString(texteLu, 10, 20);
  }
}
 

La classe java.net.URLEncoder

L'unique méthode encode () de cette classe est utile si vous voulez créer un formulaire en Java et en envoyer les résultats au serveur pour être traité par exemple par un programme CGI. Cette méthode transforme une chaîne de caractères au format x-www-form-urlencoded, c'est-à-dire que tous les espaces sont remplacés par le signe + et tous les caractères différents des lettres de l'alphabet, des chiffres et du caractère _ par leur code hexadécimal précédé du symbole %.

Méthode
public static String encode (String s)

 

Vous n'aurez normalement pas à utiliser les interfaces et les classes qui suivent, car la Machine Virtuelle Java fournit et gère automatiquement un certain nombre de protocoles et la création d'objet en fonction du contenu d'un fichier. Ces classes sont utilisées indirectement par les méthodes de la classes URLConnection.

L'interface java.net.URLStreamHandlerFactory

Cette interface est implémentée par les classes désirant gérer l'accès sous forme de flux de données à un ou plusieurs protocoles. Elle est utilisée comme paramètre de la méthode setURLStreamHandlerFactory () de la classe URL, pour modifier le gestionnaire par défaut.

Méthode
public URLStreamHandler createURLStreamHandler (String protocol)

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract URLStreamHandler ou null si le protocole protocol est refusé ou n'est pas reconnu par ce gestionnaire. L'objet renvoyé doit pouvoir créer un flux de données à partir du protocole protocol et d'une URL.

La classe java.net.URLStreamHandler

Cette classe abstract est la super classe de toutes les classes qui gère la création d'un flux de données à partir d'un protocole donné et d'une URL.
La Machine Virtuelle Java fournit un ensemble de classes pour un certain nombre de protocoles. Ces classes sont utilisées par défaut si la méthode setURLStreamHandlerFactory () de la classe URL n'a pas été appelée pour changer de gestionnaire de création de flux de données.

Constructeur
public URLStreamHandler ()
Méthodes
protected abstract URLConnection openConnection (URL url) throws IOException

Cette méthode doit ouvrir un connexion avec l'URL url et renvoyer une instance d'une classe dérivant de la classe abstract URLConnection pour permettre d'accéder à l'URL sous forme de flux de données.

protected void parseURL (URL url, String spec, int start, int limit)

Analyse la chaîne de caractères spec représentant une URL entre les caractères start et limit (exclu), pour compléter l'instance url de la classe URL. Cette méthode analyse la chaîne spec en respectant la syntaxe du protocole http, et donc s'attend à ce que start désigne le caractère suivant le symbole : du protocole, et limit le caractère # précédant la référence à une ancre.
Outrepassez cette méthode si vous voulez qu'elle analyse différemment la chaîne spec.

protected String toExternalForm (URL url)

Renvoie une chaîne de caractères correspondant à l'URL mémorisée par url.

protected void setURL (URL url, String protocol, String host,
                        int port, String file, String ref)

Permet de modifier le protocole protocol, l'hôte host, le port port, le chemin d'accès au fichier file et la référence ref mémorisés par l'objet url.

L'interface java.net.ContentHandlerFactory

Cette interface est implémentée par les classes désirant gérer le contenu d'un fichier suivant leur type mime (par exemple image/gif ou text/plain). Elle est utilisée comme paramètre de la méthode setContentHandlerFactory () de la classe URLConnection, pour modifier le gestionnaire par défaut.

Méthode
 public ContentHandler createContentHandler (String mimetype)

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract ContentHandler. Cet objet doit pouvoir créer un objet correspondant au contenu d'un fichier de type mime mimetype.

La classe java.net.ContentHandler

Cette classe abstract est la super classe de toutes les classes qui gère la création d'un objet correspondant au contenu d'un fichier d'un type mime donné.
La Machine Virtuelle Java fournit un ensemble de classes pour certains types mime. Ces classes sont utilisées par défaut si la méthode setContentHandlerFactory () de la classe URLConnection n'a pas été appelée pour changer de gestionnaire de création d'objet.

Constructeur
public ContentHandler ()
Méthode
public abstract Object getContent (URLConnection urlc) throws IOException

Cette méthode doit renvoyer un objet correspondant au contenu du fichier avec lequel la connexion urlc a été établie.

L'architecture client-serveur

Grâce à une URL, l'accès à un fichier ou une ressource est géré de manière simple : que le fichier soit sur un disque local ou sur Internet, il vous suffit de respecter les règles de construction d'une URL et le tour est joué.
Mais Java permet aussi de gérer des accès réseau plus complexe, pour réaliser par exemple un dialogue entre deux ordinateurs d'un réseau. Ce dialogue est basé sur l'architecture client-serveur, dont voici un rappel des grands principes.

Principe

Comme la programmation orientée objet, l'architecture client-serveur est une technologie informatique très utilisée actuellement.
Elle est surtout connue dans le monde des SGBD (Système de Gestion de Base de Données), mais elle s'applique aussi à d'autres domaines comme Internet, les terminaux X utilisés sous UNIX (que l'on appelle aussi serveurs X).
Son principe est assez simple mais ce sont des exemples qui vous permettront de mieux comprendre comment cette architecture s'applique concrètement.

Comme son nom l'indique, le client-serveur implique qu'il y ait au moins deux acteurs en jeu, un client et un serveur, qui communiquent entre eux, souvent à travers un réseau.
Un serveur est un programme ou par extension une machine programmée pour rendre toujours le même service, suite à une requête qui lui est adressée.
Un client est un programme ou par extension une machine qui demande à un serveur un service, en lui adressant une requête.
Gardez-bien toujours en tête ce mot service, car c'est souvent en pensant à qui rend service à l'autre que vous arriverez à déterminer qui est le client du serveur dans une architecture client-serveur.

Exemples d'utilisation


figure 12. Architecture client-serveur sur Internet

Internet que vous utilisez en ce moment, est un bon exemple d'architecture client-serveur : Les sites que vous consultez sont souvent appelés aussi des serveurs, car les programmes qui les gèrent rendent toujours le même service au client qu'est votre navigateur.
Quel service ? Le programme d'un serveur est en attente que vous lui demandiez une page du site que vous voulez visualiser. Quand votre requête lui parvient, il vous renvoie cette page. Votre navigateur de son côté est un client du serveur car il lui demande une page qu'il visualise une fois téléchargée.

Le client-serveur est souvent utilisé pour accéder à de grandes bases de données utilisées par plusieurs utilisateurs. La base de données est stockée sur une machine utilisée comme serveur. Le programme sur ce serveur a pour mission de répondre à des requêtes SQL que lui adressent des clients. Les requêtes SQL que le serveur reçoit lui permettent de modifier ou d'interroger la base de données qu'il gère, et de renvoyer au client la réponse attendue. Le client est généralement une machine de type PC dont le programme est utilisé pour mettre en page les réponses reçues du serveur.

Le principale avantage de cette architecture est qu'elle permet de séparer complètement le serveur qui généralement gère le stockage de données, du client qui cherche à y accéder.
Ainsi, dans le cas d'Internet, il est possible d'avoir des navigateurs qui tournent sous différents systèmes et même des logiciels de navigation différents sur un même système. Tous ces navigateurs sont des clients du serveur d'un site Internet auquel ils peuvent accéder simultanément.
A l'opposé, le serveur d'un site Internet peut fonctionner sur n'importe quel système, que vous n'avez d'ailleurs pas à connaître. Ce qu'il compte, c'est qu'il réponde correctement à vos requêtes, quand vous voulez voir une page hébergée sur ce site.

La clé de voûte qui permet à ce système de fonctionner sans que le client et le serveur n'aient à savoir comment ils fonctionnent l'un l'autre est l'utilisation d'un protocole commun. Ce protocole établit la norme que doit respecter le client et le serveur pour communiquer entre eux : comment établir une communication, comment un client doit envoyer une requête à un serveur et comment un serveur doit répondre à la requête du client.

Protocoles

Deux types de protocoles peuvent être utilisés sur Internet :

Port

Les serveurs des sites auxquels vous vous connectez sur Internet sont accessibles grâce à un mnémonique qui est le nom de la machine hôte (par exemple java.sun.com, www.yahoo.fr). Chaque mnémonique est associé à un identifiant numérique représentant la machine hôte qui héberge un serveur. Cet identifiant est un nombre 32 bits appelé adresse IP que l'on note généralement sous la forme d'une suite de 4 nombres séparés par des points (par exemple 194.51.83.2) : certains navigateurs affichent dans la barre d'état l'adresse IP de l'hôte d'un site, quand vous essayez de vous connectez à ce site.
Chaque machine reliée à Internet possède une adresse IP différente qui permet de la désigner de manière unique sur le réseau Internet.

Tous les systèmes d'exploitation permettent de faire fonctionner plusieurs programmes en même temps sur une machine. Si plusieurs serveurs sont hébergés sur une même machine, ils vont devoir partager l'accès physique au réseau sur cette machine. Un deuxième niveau d'identification est donc nécessaire pour désigner le programme avec lequel vous voulez vous connecter sur une machine donnée.
A chaque programme désirant communiquer sur Internet est associé un port unique, qui est un nombre 16 bits compris entre 0 et 65535. Les ports dont le nombre est compris entre 0 et 1023 sont réservés à des services particuliers et ne doivent pas être utilisés par les serveurs que vous programmez.

Globalement, un programme est identifié sur Internet par l'adresse IP de la machine sur lequel il fonctionne et le numéro du port auquel il est associé.

Accès via les sockets

Chaque extrémité d'une connexion entre un client et un serveur est appelée un socket. Un socket est une représentation logique du point de branchement d'un programme au réseau.

Pour programmer une architecture client serveur utilisant le protocole TCP (Transport Control Protocol), il vous faut réaliser, grâce aux classes ServerSocket et Socket qui suivent, un programme faisant office de serveur sur une machine hôte et un autre utilisé comme client sur une autre machine.
Pour vous permettre de tester les programmes serveur et client sur la même machine, le client peut essayer de se connecter à la machine localhost qui représente la machine locale.


figure 13. Utilisation des sockets en Java

Comme le montre la figure précédente, le programme serveur doit créer une instance de la classe ServerSocket en précisant le numéro de port sur lequel il attend les demandes de connexion des programmes clients. Le serveur appelle ensuite la méthode accept () de cette classe pour se mettre en attente de demande de connexion.
Une fois qu'un client s'est connecté, une instance de la classe Socket est renvoyée. Le serveur peut alors grâce au méthodes de cette classe obtenir des flux de données en lecture et en écriture pour communiquer avec le programme client.

Le programme client de son côté se connecte à un programme serveur en créant une instance de la classe Socket, en précisant l'adresse Internet de la machine hôte et le numéro de port sur lequel le serveur attend les demandes de connexions.
Comme pour le programme serveur, une fois qu'il a obtenu une instance de cette classe, il peut obtenir des flux de données en lecture et en écriture.

Chacun des programmes serveurs et clients pouvant envoyer et lire des données, tout est alors prêt pour communiquer des données dans les deux sens entre les programmes.
Pour un fonctionnement correct, il suffit que quand le client écrit sur le flux de données de sortie de son socket, le serveur soit en lecture sur le flux de données d'entrée de son socket et inversement.

La classe java.net.InetAddress

Cette classe final permet de manipuler l'adresse Internet d'une machine hôte. Elle est utilisée par les classes ServerSocket, Socket et DatagramPacket.

Méthodes
public static synchronized InetAddress getByName (String host)
                               throws UnknownHostException

Renvoie une instance de la classe InetAddress représentant l'adresse Internet de la machine host.

public static synchronized InetAddress [ ] getAllByName (String host)
                               throws UnknownHostException

Renvoie toutes les adresses Internet de la machine host.

public static InetAddress getLocalHost () throws UnknownHostException

Renvoie une instance de la classe InetAddress représentant l'adresse Internet de la machine locale. Très pratique pour tester sur une même machine les programmes client et serveur. Equivalent à getByName (null) ou getByName ("localhost").

public String getHostName ()

Renvoie le nom de la machine hôte.

public byte [ ] getAddress ()

Renvoie l'adresse IP mémorisée par une instance de la classe InetAddress. Le tableau renvoyé contient les 4 nombres d'une adresse IP qui sont séparées par des points (par exemple 194.51.83.2).

public int hashCode ()
public boolean equals (Object obj)
public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer un objet de classe InetAddress à un objet ou renvoyer une chaîne de caractères décrivant une adresse Internet.

Exemples

Applets EchoClient et PaperBoardClient.

La classe java.net.Socket

Cette classe final permet de manipuler un socket. Vous pouvez en obtenir une instance de deux manières différentes, suivant que vous réalisez le programme client ou le serveur :

Une fois obtenue une instance de la classe Socket, il est possible d'obtenir côté client comme côté serveur un flux de données d'entrée et un flux de données de sortie, grâce aux méthodes getInputStream () et getOutputStream (). Ces méthodes renvoient des instances de classes dérivant des classes InputStream et OutputStream dont les méthodes permettent de de lire et d'envoyer des données entre le client et le serveur.

Constructeurs
public Socket (String host, int port)
           throws UnknownHostException, IOException
public Socket (String host, int port, boolean stream)
           throws IOException

Ces constructeurs permettent de créer une instance de la classe Socket et d'obtenir pour un programme client une connexion avec le programme serveur de la machine host en attente sur le port port. Si stream (égal à true par défaut) est égale à false, un socket de datagrammes est créé.

public Socket (InetAddress address, int port)
           throws IOException
public Socket (InetAddress address, int port, boolean stream)
           throws IOException

Ces constructeurs fonctionnent comme les deux premiers, mais prennent comme premier paramètre une instance de la classe InetAddress.

Méthodes
public InputStream getInputStream () throws IOException
public OutputStream getOutputStream () throws IOException

Ces méthodes permettent d'obtenir un flux de données en lecture ou un flux de données en écriture, pour communiquer avec le socket distant.

public synchronized void close () throws IOException

Ferme la connexion avec le socket distant.

public InetAddress getInetAddress ()
public int getPort ()

Ces méthodes renvoient l'adresse Internet et le port du socket distant auquel le socket est connecté.

public int getLocalPort ()

Renvoie le port local sur lequel le socket est connecté.

public static synchronized void setSocketImplFactory (SocketImplFactory fac)
                         throws IOException, SecurityException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de création de sockets, différent de celui fourni par défaut. Cette méthode static ne peut être appelée qu'une seule fois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant le socket.

Exemples

Applications EchoServer et PaperBoardServer.
Applets EchoClient et PaperBoardClient.

La classe java.net.ServerSocket

Cette classe final est utilisée par un programme serveur pour gérer l'attente de demande de connexion d'un programme client sur un port de la machine hôte du serveur.

Constructeurs
public ServerSocket (int port) throws IOException
public ServerSocket (int port, int count) throws IOException

Ces constructeurs permettent de créer un socket de serveur en attente sur le port port. Pour autoriser la connexion anonyme d'un client, utilisez un port est égal à 0. count (égal à 50 par défaut) permet de spécifier le nombre maximum de demande de connexions en attente que le serveur termine d'exécuter la méthode accept ().

Méthodes
public Socket accept () throws IOException

Attend la demande de connexion d'un programme client, et renvoie un socket une fois la connexion établie.

public void close () throws IOException

Ferme le socket du serveur.

public InetAddress getInetAddress ()
public int getLocalPort ()

Ces méthodes renvoient l'adresse Internet et le port local sur lequel le socket du serveur est connecté.

public static synchronized void setSocketFactory
                      (SocketImplFactory fac) throws IOException         

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de création de socket de serveur, différent de celui fourni par défaut. Cette méthode static ne peut être appelée qu'une seule fois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant le serveur.

Exemples

Applications EchoServer et PaperBoardServer.

EchoLe client serveur d'écho

Ce premier exemple de client serveur se décompose en deux programmes : une application pour le serveur et une applet pour le client. Vous pouvez tester cet exemple sur votre ordinateur car l'applet se connecte sur le serveur de la machine locale, où vous pouvez lancer l'application serveur.
Cet exemple réalise une opération très simple d'écho : le serveur ne fait que renvoyer en l'état les données que le client lui envoie, jusqu'à ce qu'il rencontre un retour chariot.
Il faut lancer l'application du serveur avant de lancer l'applet du client.

Voici le programme du serveur. Recopiez-le dans un fichier EchoServer.java, que vous compilez avec l'instruction javac EchoServer.java pour ensuite l'exécuter avec java ou Java Runner, grâce à l'instruction java EchoServer : :

import java.net.*;
import java.io.*;
 
public class EchoServer
{
  public static void main (String args [])
  {
    try
    {
      // Création d'un serveur sur le port 13267
      ServerSocket server = new ServerSocket (13267);
      // Attente de la connexion d'un client
      Socket       socket = server.accept ();
 
      System.out.println ("Connexion sur le socket : " + socket);
 
      // Récupération des flux d'entrés et de sortie
      InputStream  fluxEntree = socket.getInputStream ();
      OutputStream fluxSortie = socket.getOutputStream ();
 
      char caractereLu;
      // Renvoie de chaque caractère lu au client
      // jusqu'à ce que ce caractère soit un retour chariot
      while ((caractereLu = (char)fluxEntree.read ()) != '\n')
        fluxSortie.write (caractereLu);
        
      server.close ();
    }
    catch (IOException e)
    {
      System.out.println (e);
    }  
  }
}

Une fois programmé le serveur, il faut réaliser un programme client. Celui-ci est une applet simple qui envoie au serveur tous les caractères saisis au clavier et affiche les caractères lus à partir du serveur sous la forme d'une chaîne de caractères (à mettre dans un fichier EchoClient.java) :

import java.applet.Applet;
import java.awt.*;
import java.net.*;
import java.io.*;
 
public class EchoClient extends Applet
{
  String       texteLu = "";
  InputStream  fluxEntree;
  OutputStream fluxSortie;
  
  // Méthode appelée par le système à l'initialisation de l'applet
  public void init ()
  {
    try 
    {
      // Récupération de l'adresse de l'hôte local
      InetAddress adresse = InetAddress.getLocalHost ();
      // Ouverture d'une connexion sur le port 13267 de cet hôte
      Socket      socket  = new Socket (adresse, 13267);
      
      // Récupération des flux d'entrés et de sortie
      fluxEntree = socket.getInputStream ();
      fluxSortie = socket.getOutputStream ();
    }
    catch (IOException e)
    {
      texteLu = "Probleme de connexion";
    }
  }
 
  // Méthode appelée par le système pour mettre à jour le dessin de l'applet
  public void paint (Graphics gc)
  {
    gc.drawString (texteLu, 10, 20);
  }
  
  // Méthode appelée par le système quand une touche du clavier est enfoncée
  public boolean keyDown (Event evt, int key)
  {
    if (fluxSortie != null)
      try
      {
        // Envoie au serveur du caractère lu puis relecture
        fluxSortie.write(key);
        char caractereLu = (char)fluxEntree.read ();
        
        // Ajout du caractère et redessin de l'applet
        texteLu += caractereLu;          
        repaint();
      }
      catch (IOException e)
      { }
    return true;
  }
}

Voici un exemple de code HTML qui vous permettre d'appeler cette applet (à mettre par exemple dans un fichier EchoClient.html et à exécuter avec appletviewer ou Applet Runner, grâce à l'instruction appletviewer EchoClient.html) :

<applet code="EchoClient" width=200 height=30> </applet>

EchoLe paper board Internet

Ce deuxième exemple de client serveur beaucoup plus élaboré se décompose toujours en deux programmes : une application pour le serveur et une applet pour le client.
Chaque utilisateur visualisant cette applet peut partager un dessin qu'il dessine avec la souris, avec toutes les autres personnes connectées au serveur. Pour saisir un élément de dessin, il suffit de déplacer la souris en maintenant son bouton enfoncé.
Pour permettre plusieurs connexions simultanées de clients au serveur, ce dernier lance un thread gérant chaque connexion. Chacun de ces threads a pour mission d'attendre les requêtes de chacun des clients.
Quatre types différents de requêtes sont gérées :

!

PaperBoardServerRunnerL'applet du client ne peut fonctionner que si le serveur du paper board est en marche sur www.eteks.com. Si l'applet ci-dessous vous indique au moins une connexion, tout est OK ! Si vous êtes connectés à Internet via un proxy, il est possible que cela ne puisse pas fonctionner.
Trouvez d'autres personnes pour se connecter au serveur et partagez vos dessins : Plus on est de fous, plus on rit !....

 

Applet PaperBoardClient

Voici le programme du serveur qui tourne sur www.eteks.com (A mettre dans un fichier PaperBoardServer.java, et exécuté avec java ou Java Runner) :

import java.net.*;
import java.io.*;
import java.util.*;
 
public class PaperBoardServer implements Runnable
{
  public static int     port = 26197;
  public static String  requeteFin   = "FIN";
  public static String  requeteListe = "LISTE";
  public static String  requeteAjout = "AJOUT";
  public static String  requeteConnexion = "CONNEXION";
 
  private static ServerSocket serveur;
  
  public static void main (String args [])
  {
    if (lancerServeur () == null)
      System.exit (-1);
  }
  
  // lancerServeur () peut être appelée par une servlet
  // pour éviter de lancer une Machine Virtuelle supplémentaire
  // sur le serveur où est hébergé le site
  public static ServerSocket lancerServeur ()
  {
    if (serveur == null)
      try
      {
        // Création d'un serveur sur le port 26197
        serveur = new ServerSocket (port); 
        // Lancement d'un thread d'attente de connexion
        new Thread (new PaperBoardServer ()).start ();
      }
      catch (IOException e)
      {
        System.out.println (e);
        return null;
      }
      
    return serveur;
  }
 
  public void run ()
  {    
    try
    {
      // Boucle sans fin d'attente de connexion
      while (true)
      {
        // Attente de la connexion d'un client
        Socket socket = serveur.accept ();
        // Démarrage d'un nouveau thread pour gérer la connexion
        new ThreadSocket (socket).start ();
      }  
    }
    catch (IOException e)
    {
      System.out.println (e);
    }  
    finally
    {
      try
      {
        // Fermeture du serveur
        serveur.close ();
        serveur = null;
      }
      catch (IOException e)
      {
        System.out.println (e);
      }  
    }
  }
}
 
class ThreadSocket extends Thread
{
  static private Vector listePolylines = new Vector (100);
  static private int    connexions;
  private        Socket socket;
 
  public ThreadSocket (Socket socket)
  {
    this.socket = socket;
  }
 
  public void run ()
  {
    try
    {
      // Récupération des flux d'entrés et de sortie
      DataInputStream fluxEntree = new DataInputStream (
                        new BufferedInputStream (socket.getInputStream ()));
      PrintStream fluxSortie = new PrintStream (
                        new BufferedOutputStream (socket.getOutputStream ()), true);
   
      // Augmentation du nombre de connexions au serveur
      connexions++;
      
      String chaineLue;
      // Lecture sur le flux d'entrée tant que la requête FIN n'est pas arrivée
      while (   (chaineLue = fluxEntree.readLine ()) != null
             && !chaineLue.equals (PaperBoardServer.requeteFin))
      {
        if (chaineLue.startsWith (PaperBoardServer.requeteListe))
        {
          // Si la liste des polylines est demandée, elles sont
          // renvoyées séparées par des tabulations
          for (Enumeration e = listePolylines.elements (); 
               e.hasMoreElements (); )
            fluxSortie.print (e.nextElement ().toString () + '\t');
          fluxSortie.write ('\n');
        }
        else if (chaineLue.equals (PaperBoardServer.requeteConnexion))
        {
          // Renvoi du nombre de connexions au serveur
          fluxSortie.print (String.valueOf (connexions));
          fluxSortie.write ('\n');
        }
        else if (chaineLue.startsWith (PaperBoardServer.requeteAjout))
        {
          // Si le vecteur arrive à saturation, il est vidée
          // (ceci pour éviter que le dessin ne devienne trop dense)
          if (listePolylines.size () == listePolylines.capacity ())
            listePolylines.removeAllElements ();
          // La nouvelle polyline reçue est ajoutée à la liste
          listePolylines.addElement (
            chaineLue.substring (PaperBoardServer.requeteAjout.length ()));
        }
      }
      
      fluxEntree.close ();
      fluxSortie.close ();
      socket.close ();
    }
    catch (IOException e)
    {
      System.out.println (e);
    }  
    
    connexions--;
  }
}

Une fois programmé le serveur, il faut réaliser un programme client. Celui-ci est l'applet ci-dessus qui envoie au serveur les polylines saisies par l'utilisateur, et demande au serveur toutes les secondes la liste courante de toutes les polylines que celui-ci mémorise (à mettre dans un fichier PaperBoardClient.java) :

import java.applet.Applet;
import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
 
public class PaperBoardClient extends Applet implements Runnable
{
  private String          message;
  private Socket          socket;
  private DataInputStream fluxEntree;
  private PrintStream     fluxSortie;
  
  private Vector          listePolylines = new Vector (100);
  private Polygon         polylineCourante;
  
  private int             connexions;
  
  // Méthode appelée par le système à l'affichage de l'applet
  public void start ()
  {
    setBackground (Color.white);
    try 
    {
      // Récupération de l'adresse de l'hôte www.eteks.com
      InetAddress adresse = InetAddress.getByName ("www.eteks.com");
      // Ouverture d'une connexion sur le port 26197 de cet hôte
      socket = new Socket (adresse, PaperBoardServer.port);
      
      // Récupération des flux d'entrés et de sortie
      fluxEntree = new DataInputStream (
                     new BufferedInputStream (socket.getInputStream ()));
      fluxSortie = new PrintStream (
                     new BufferedOutputStream (socket.getOutputStream ()), true);
        
      // Lancement d'un thread qui interroge à intervalle régulier 
      // la liste des polylines enregistrées sur le serveur                
      new Thread (this).start ();
    }
    catch (IOException e)
    {
      message = "Probleme de connexion avec le serveur";
    }
  }
 
  // Méthode appelée par le système à la disparition de l'applet
  public void stop ()
  {
    try
    {
      // Envoi d'une requête FIN et fermeture des flux
      fluxSortie.println (PaperBoardServer.requeteFin);
      fluxSortie.close ();
      fluxEntree.close ();
      socket.close ();
    }
    catch (IOException e)
    { }
    
    fluxSortie = null;
  }
 
  public void run ()
  {
    try
    {
      while (fluxSortie != null)
      {
        // Envoi d'une requête CONNEXION pour récupérer le 
        // nombre de clients connectés au serveur
        fluxSortie.print (PaperBoardServer.requeteConnexion);
        fluxSortie.write ('\n');
 
        message = fluxEntree.readLine () + " connexions";
      
        // Envoi d'une requête LISTE pour récupérer 
        // la liste de toutes les polylines du serveur
        fluxSortie.print (PaperBoardServer.requeteListe);
        fluxSortie.write ('\n');
 
        String liste = fluxEntree.readLine ();
        
        // Vidange de la liste pour la remettre à jour
        listePolylines.removeAllElements ();
        StreamTokenizer tokens = new StreamTokenizer (
                                   new StringBufferInputStream (liste));
        tokens.parseNumbers ();
        tokens.ordinaryChar ('\t');
        tokens.whitespaceChars (' ', ' ');
    
        // Décodage de la liste de points 
        while (tokens.nextToken () != StreamTokenizer.TT_EOF)
        {
          Polygon polyline = new Polygon ();
          // Récupération des couples de valeurs (x,y)
          // d'une polyline jusqu'à la prochaine tabulation
          while (tokens.ttype != '\t')
          {
            int x = (int)tokens.nval;
            tokens.nextToken ();
            int y = (int)tokens.nval;
            tokens.nextToken ();
            polyline.addPoint (x, y);
          }
          // Ajout de la polyline à la liste
          listePolylines.addElement (polyline);
        }    
        
        repaint ();
        // Arrête le thread pendant 1 s avant de lancer 
        // une nouvelle demande de mise à jour
        Thread.sleep (1000);
      }
    }
    catch (InterruptedException e) 
    { }
    catch (IOException e)
    { }
  }
    
  // Méthode appelée par le système pour mettre à jour le dessin de l'applet
  public void paint (Graphics gc)
  {
    if (message != null)
      gc.drawString (message, 10, 20);
 
    // Dessin de toutes les polylines 
    // et de la polyline courante si elle existe
    for (Enumeration e = listePolylines.elements (); 
         e.hasMoreElements (); )
      drawPolyline (gc, (Polygon)e.nextElement ());
 
    if (polylineCourante != null)
      drawPolyline (gc, polylineCourante);
  }
  
  private void drawPolyline (Graphics gc, Polygon polyline)
  {
    for (int i = 1; i < polyline.npoints; i++)
      gc.drawLine (polyline.xpoints [i - 1], polyline.ypoints [i - 1],
                   polyline.xpoints [i],     polyline.ypoints [i]);
  }
  
  // Les méthodes mouseDown (), mouseDrag (), mouseUp () sont
  // appelées par le système à l'enfoncement du bouton de la souris,
  // au déplacement du pointeur, et au relâchement du bouton
  public boolean mouseDown (Event evt, int x, int y)
  {
    polylineCourante = new Polygon ();
    polylineCourante.addPoint (x, y);
    return true;
  }
 
  public boolean mouseDrag (Event evt, int x, int y)
  {
    polylineCourante.addPoint (x, y);
    paint (getGraphics ());
    return true;
  }
 
  public boolean mouseUp (Event evt, int x, int y)
  {
    polylineCourante.addPoint (x, y);
    
    // Construction d'une requête AJOUT avec la liste des points
    // de la nouvelle polyline
    fluxSortie.print (PaperBoardServer.requeteAjout);
    for (int i = 0; i < polylineCourante.npoints; i++)
      fluxSortie.print (String.valueOf (polylineCourante.xpoints [i])
                        + ' ' + polylineCourante.ypoints [i] + ' ');
         
    fluxSortie.write ('\n');
    listePolylines.addElement (polylineCourante);
    paint (getGraphics ());
    return true;
  }
}

Vous pouvez tester éventuellement ce programme sur votre machine locale en lançant le serveur PaperBoardServer, et en remplaçant dans l'applet PaperBoardClient le nom du site Internet "www.eteks.com" par "localhost".
Ce programme est inspiré du Groupboard disponible à l'adresse http://www.groupboard.com.

 

Vous n'aurez normalement pas à utiliser la classe et l'interface qui suivent, utilisées par la Machine Virtuelle Java pour réaliser l'implémentation des sockets.

La classe java.net.SocketImpl

Cette classe abstract permet de gérer un socket et la connexion au socket d'un serveur. Elle est utilisée pour les sockets côté client comme côté serveur. Elle comporte des champs et des méthodes protected qui sont utilisées pour réaliser les services des méthodes des classes précédentes Socket et ServerSocket.

Champs
protected FileDescriptor fd
protected InetAddress address
protected int port
protected int localport
Constructeur
public SocketImpl ()
Méthodes
protected abstract void create (boolean stream) throws IOException
protected abstract void connect (String host, int port)
                          throws IOException
protected abstract void connect (InetAddress address, int port)
                          throws IOException
protected abstract void bind (InetAddress host, int port)
                          throws IOException
protected abstract void listen (int count) throws IOException
protected abstract void accept (SocketImpl s) throws IOException
protected abstract InputStream getInputStream () throws IOException
protected abstract OutputStream getOutputStream () throws IOException
protected abstract int available () throws IOException
protected abstract void close () throws IOException
protected FileDescriptor getFileDescriptor ()
protected InetAddress getInetAddress ()
protected int getPort ()
protected int getLocalPort ()
 
public String toString ()
 

L'interface java.net.SocketImplFactory

Cette interface est implémentée par les classes désirant gérer la création de sockets. Elle est utilisée comme paramètre des méthodes setSocketImplFactory () de la classe Socket et setSocketFactory () de la classe ServerSocket, pour modifier le gestionnaire par défaut.

Méthode
public SocketImpl createSocketImpl ()

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract SocketImpl.

Accès via les datagrammes

Pour programmer une architecture client serveur utilisant le protocole UDP (User Datagram Protocol), il faut utiliser les classes DatagramPacket représentant un paquet de données (ou datagramme) à recevoir ou envoyer, et DatagramSocket utilisé pour recevoir et envoyer des datagrammes.

Contrairement au protocole TCP, le protocole UDP ne maintient pas de connexion permanente entre deux machines. Chaque datagramme est indépendant l'un de l'autre : il comporte un tableau de données, l'adresse Internet et le port de la machine à laquelle il est destiné.

La classe java.net.DatagramPacket

Cette classe final représente un datagramme. Le premier constructeur est utilisé pour créer un datagramme à recevoir, le second pour créer un datagramme à envoyer à une machine.

Constructeurs
public DatagramPacket (byte ibuf [ ], int ilength)

Construit une instance de la classe DatagramPacket utilisé pour recevoir un datagramme dont les paquets de données de longueur ilength seront stockées dans le tableau ibuf. Si le datagramme reçu est plus long que ilength, les données restantes ne sont pas recopiées dans ibuf.

public DatagramPacket (byte ibuf [ ], int ilength,
                         InetAddress iaddr, int iport)

Construit une instance de la classe DatagramPacket utilisé pour envoyer un paquet de données ibuf de longueur ilength, au port iport d'une machine d'adresse Internet iaddr.

Méthodes
public InetAddress getAddress ()

Renvoie l'adresse Internet de la machine dont provient ou auquel est destiné ce datagramme.

public int getPort ()

Renvoie le port de la machine dont provient ou auquel est destiné ce datagramme.

public byte[] getData ()
public int getLength ()

Ces méthodes renvoient le tableau où sont stockées les données d'un datagramme et la longueur des données à recevoir (ou reçues) ou à envoyer.

La classe java.net.DatagramSocket

Cette classe permet de recevoir et envoyer des datagrammes, grâce aux méthodes receive () et send ().

Constructeurs
public DatagramSocket () throws SocketException

Construit une instance de la classe DatagramSocket. Le port utilisé pour recevoir ou envoyer des datagrammes est le premier disponible sur la machine locale.

public DatagramSocket (int port) throws SocketException

Construit une instance de la classe DatagramSocket. Le port port sur la machine locale est utilisé pour recevoir ou envoyer des datagrammes.

Méthodes
public int getLocalPort ()

Renvoie le port de la machine locale sur lequel l'envoi ou la réception de datagrammes s'effectue.

public void synchronized receive (DatagramPacket packet) throws IOException

Permet de recevoir un paquet de données dans le datagramme packet. Cette méthode met en attente le thread courant jusqu'à réception d'un datagramme.

public void send (DatagramPacket packet) throws IOException

Permet d'envoyer le datagramme packet.

public synchronized void close ()

Ferme le socket.

protected synchronized void finalize ()

Page d'accueilFindIt !ContactLa gestion des fichiers et des flux de donnéesLes applications et les appletsDébut de la page
© Copyrights 1997-2023 Emmanuel PUYBARET / eTeks
- Tous droits réservés -
Table des matièresHiérarchie des classes