Classes JAVA pour la programmation réseau

WB01624_.gif (281 octets) RETOUR

Les flux (Streams)

Stream : Objet JAVA possédant la caractéristique de pouvoir envoyer ou recevoir des données

Java.io est le package dédié à la gestion des entrées/sorties. Il intègre des classes de gestion de fichier au sens classique du terme.

Outre ces classes, le package java.io possède un nombre important de classes dédiées à la gestion des flux de données.

Les classes de base de java.io sont :

  • InputStream pour gérer des données en entrée (lecture),

  • OutputStream pour gérer des données en sortie (écriture).

Ces deux classes abstraites ne sont pas utilisées directement mais plutôt comme intermédiaires vers des sous-classes correspondant mieux à la finalité désirée.

Ces autres classes de gestion de flux de java.io ont pour but de réaliser le formatage automatique des données (type de valeur, manière avec laquelle les données sont transmises, ...) vers le type le plus adapté à l'application souhaitée.

Exemple 1 : Lecture d'un fichier texte et affichage de son contenu à l'écran

BufferedReader dis = null ;
try {
  InputStream is =
    new FileInputStream("d:\\text.txt") ;
  dis = new BufferedReader(
      new InputStreamReader(is));
  String l ;
  try {
    while ( (l=dis.readLine())!=null ){
      System.out.println(l) ; }
    dis.close() ; }
  catch(IOException e) { } ; }
catch(FileNotFoundException e) {
  System.out.println(e) ; }

Exemple 2 : Ouverture d'une Socket et association d'un flux de sortie à cette socket

Socket s ;
String hote = "raphaello.univ-fcomte.fr" ;
int port = 5555 ;
try {
  s = new Socket(hote,port) ;
  OutputStream os = s.getOutputStream() ;
  DataOutputStream dos =
                new DataOutputStream(os) ;
  ...
  dos.close() ;}
catch ( UnknownHostException e) { } ;
catch ( IOException e) { } ;

Une fois les flux ouverts, il est possible d'utiliser toutes les fonctions disponibles pour le transfert des données désirées (variables simples, objets, ...)

Exemples de sous-classes de InputStream et OutputStream

  • BufferedReader : Lecture de texte depuis un flux d'entrée caractère -> caractères, tableaux et chaînes de caractères.

  • BufferedWriter : Ecriture de texte dans un flux de sortie caractère -> caractères, tableaux et chaînes de caractères.

  • DataInputStream : Lecture de données Java primitives.

  • DataOutputStream : Ecriture de données Java primitives.

  • FileInputStream : Lecture d'octets depuis un fichier.

  • FileOutputStream : Ecriture d'octets dans un fichier.

  • ObjectInputStream : Lecture d'objets Java par desérialisation.

  • ObjectOutputStream : Ecriture d'objets Java par sérialisation.

Les Threads

Thread : Objet JAVA possédant la caractéristique de pouvoir s'exécuter en parallèle au programme qui lui a donné naissance (processus léger)

Caractéristiques :

  • Gestion par le système de l'attribution des temps de calcul aux Threads en cours d'exécution

  • Partage de la même zone mémoire que le programme de naissance -> mémoire partagée

Ecriture d'une classe thread :

  • Extension de la classe java.lang.Thread

Surcharge de la méthode public void run() avec une fonction implantant l'équivalent de la fonction main pour un programme classique

  • Emploi d'une instance de classe thread :

Instanciation d'une variable de la classe étendant Thread

Exécution de la méthode start héritée de Thread

Exemple :

public class MyThread extends Thread {
  private boolean ok = true ;

  public void run() {
    while ( ok ) {
      ...
      }
    }

  public void arret() {
    ok = false ;
    }
  }

...
MyThread th = new Thread() ;
th.start() ;
...
th.arret() ;
...

Exécution de la méthode start héritée de Thread

Autre façon d'écrire des Threads

  • Implantation de l'interface Runnable dans une classe

-> Ecriture dune méthode public void run() implantant la fonction à exécuter quand le Thread est lancé par start

  • Utilisation d'un objet instanciant cette classe pour instancier un nouveau Thread selon le constructeur Thread(Runnable r)

Exemples :

public class ThreadInit implements Runnable {
  private boolean ok = true ;

  public void run() {
    while ( ok ) {
      ...
      }
    }
  }

...
Thread th = new Thread(new ThreadInit()) ;
th.start() ;
...

ou bien

public class MyThread implements Runnable {
  private boolean ok = true ;

  public void run() {
    while ( ok ) {
      ...
      }
    }

  public void start() {
    Thread th = new Thread(this) ;
    th.start() ;
    }
  }

Les problèmes de synchronisation

Emploi de threads -> problème de synchronisation lors de l'accès de deux ou plusieurs threads à la même zone de mémoire partagée

Exemple : Applette1

  • Une applette définit un objet instanciant la classe Coordonnee (deux entiers x et y initialisés à la valeur 0

  • Deux Threads partagent cette instance et y accèdent de manière concurente l'un pour la modifier (incrémentation des deux entiers de 1), l'autre pour l'afficher

  • Un compteur totalise le nombre de différences constatées entre les champs x et y, qui augmente régulièrement au cours du temps

Source

Utilisation de la directive synchronized pour créer des blocs d'instructions ne pouvant être interrompus

Synchronisation sur deux types d'éléments de code :

  • Des méthodes

Exemple :

public synchronized void set(int xx,int yy){
  cx = xx ;
  cy = yy ;
  }

Lorsqu'un code exécuté dans un Thread essaie de lancer une fonction synchronisée d'un objet, il est bloqué tant que cet objet n'est pas relaché (si celui-ci est utilisé par ailleurs)

  • Des portions de code

Exemple :

   Coordonnee c = new Coordonnee() ; 
   int x ; 
   int y ; 
   ...
   synchronized (c) {
      x = c.x() ;
      y = c.y() ; }
   System.out.println(x+" "+y) ;

Marquage d'un bloc de code dans lequel on ne peut pas entrer tant que l'objet spécifié dans l'instruction synchronized n'est pas relaché. Quand c'est fait, le bloc de code est exécuté et les autres Threads ne peuvent plus entrer dans les méthodes synchonisées de c.

Exemple : Modification de l'Applette1 pour vérouiller set durant les lectures de x et de y

Source

Le package java.net

Introduction

Le package java.net contient toutes les classes orientées réseau bas niveau de l'API JAVA.

Les U.R.L.

java.net.URL est la classe de base JAVA pour la représentation des URLs Internet.

Cette classe permet l'instanciation d'objets auxquels on peut déléguer le téléchargement de fichiers via Internet.

Exemple : Lecture de la première ligne de texte d'un fichier HTML

import java.net.URL ;
...
URL u ;
DataInputStream is ;
try { 
  u = new URL(
"http://raphaello.
          univ-fcomte.fr/java/default.html");
  try { 
    dis = new DataInputStream(u.openStream());
    String ligne = dis.readLine() ; }
  catch (Exception e) {
    System.out.println(e) ; } }
catch (MalformedURLException e) {
  System.out.println(e) ; }

Elle est utilisée dans les méthodes de la classe Applet pour les téléchargements de fichiers multimédia.

Exemple : Une Applette téléchargant un fichier image dans sa fonction init

import java.applet.Applet ;
import java.net.URL ;
import java.net.MalformedURLException ;
import java.awt.Graphics ;
import java.awt.Image ;

public class AppletURL extends Applet {
  private Image i = null ;

  public void init() {
    URL u ;
    try { 
      u = new URL("
http://raphaello.
          univ-fcomte.fr/JavaReseau/r1.gif");
      i = getImage(u) ; }
    catch (MalformedURLException e) {
      }
    }

  public void paint(Graphics g) {
    if ( i != null )
      g.drawImage(i,10,10,this) ;
    }
  }

Les sockets

Les données transitent sur l'Internet dans des paquets d'octets de taille limitée appelés datagrammes, formés d'un entête (adresse, numéro de port de l'expéditeur et du destinataire,…) et d'une charge utile composée des données. Un transfert unique peut nécessiter plusieurs paquets -> difficultés de réorganisation de l'information à l'arrivée. Les sockets permettent la gestion d'un transfert de données comme un flux ordinaire (les paquets sont triés à l'arrivée).

Les classes java.net.Socket et java.net.ServerSocket sont les deux classes de base pour l'implantation des sockets TCP/IP sous JAVA.

7 opérations élémentaires sont assurées par un Socket :

connexion à une machine distante (Socket),

envoi de données (Socket),

réception de données (Socket),

fermeture d'une connexion (Socket),

attachement à un port (ServerSocket),

attente de demande de connexion émanant de machines distantes (ServerSocket),

acceptation de demandes de connexion sur le port local (ServerSocket).

Mise en œuvre :

La Socket est créée sur le client.

Le ServerSocket fonctionne sur le serveur en attente de connexion (méthode accept()) ;.

La nouvelle Socket tente de se connecter sur le serveur distant.

Après détection d'ouverture de connexion, le ServerSocket génère une Socket pour communiquer avec le client.

Une fois la connexion établie, les systèmes locaux et distant établissent un canal de communication par flux à partir de leurs Sockets de manière à échanger des données.

Lorsque les échanges sont terminés, l'un des interlocuteurs clôt la communication.

  • Socket permet l'instanciation de sockets (sur les clients et serveurs) pour initier et gérer les transferts de données au cours d'une communication.

Exemple : Cette applette tente d'ouvrir des sockets sur la machine raphaello.univ-fcomte.fr pour les ports 20 à 24. Elle affiche en noir ceux pour lesquels il n'y a pas de serveur et en rouge ceux pour lesquels il y a un serveur et donc une réponse.

import java.net.* ;
import java.io.* ;
import java.applet.Applet ;
import java.awt.* ;

public class VerificationPorts
       extends Applet {
  Socket s ;
  String hote = "raphaello.univ-fcomte.fr" ;

  public void paint(Graphics g) {
    int port ;
    int y = 0 ;
    for ( port = 0 ; port < 50 ; port++ ) {
      try {
        s = new Socket(hote,port) ;
        g.setColor(Color.red) ; }
      catch ( UnknownHostException e) { }
      catch ( IOException e) {
        g.setColor(Color.black) ; }
      g.drawString(new Integer(port)
                   .toString(),10,y*15+15) ;
      y++ ; }
    }
  }

Constructeurs :

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

public Socket(InetAddress address, int port) throws IOException

public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException

Toutes ces fonctions génèrent une IOException en cas de problème à l'exécution.

host (String) : nom de la machine vers laquelle la socket est créée.

addresse (InetAddress) : adresse IP de la machine vers laquelle la socket est créée.

port (int) : numéro du port sur lequel la socket est créée.

localAddr (InetAddress) : adresse IP locale auquelle la socket est associée.

localPort (int) : numéro du port local auquel la socket est associée.

Quelques fonctions utiles:

public void close() throws IOException : ferme la socket

public inputStream getInputStream() throws IOException : retourne le flux d'entrée associé à la socket

public outputStream getOutputStream() throws IOException : retourne le flux de sortie associé à la socket

  • ServerSocket permet l'instanciation de variables implantant des écouteurs de ports TCP/IP pour la détection de requêtes d'ouverture de Socket (sur les serveurs). Cette classe ouvre une socket sur le client correspondant.

Exemple : Instanciation d'un ServerSocket sur le port 5555

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

public class ServeurMinimum {

  public static void main(String [] args) {
    ServerSocket srv ;
    int port = 5555 ;
    try {
      srv = new ServerSocket(port) ; }
    catch(IOException e) { }
    }
  }

Dans l'exemple précédent, le ServerSocket est instancié mais, pas utilisé et le programme s'interrompt immédiatement.

-> Utilisation de la méthode public Socket accept() pour détecter et accepter une connexion

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

public class ServeurMinimum2 {

  public static void main(String [] args) {
    ServerSocket srv ;
    int port = 5555 ;
    try {
      srv = new ServerSocket(port) ;
      while ( true ) {
        Socket connexion = srv.accept() ;
        ...
        connexion.close() ; } }
    catch(IOException e) { }
    }
  }

Pour éviter de bloquer l'exécution du programme pendant l'attente, on place l'appel à la méthode accept() dans un Thread distinct.

Exemple

Constructeur :

public ServerSocket(int port) throws IOException

Toutes ces fonctions génèrent une IOException en cas de problème à l'exécution.

port (int) : numéro du port sur lequel le ServerSocket est créé et mis en attente.

Quelques fonctions utiles:

public void close() throws IOException : ferme le ServerSocket

public Socket accept() throws IOException : place le ServerSocket en attente de requête d'ouverture de sockette. Cette attente est bloquante. Une sockette est automatiquement générée et retournée lors de cette requête.