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 :
Ecriture d'une classe thread :
Surcharge de la méthode public void run() avec une fonction implantant
l'équivalent de la fonction main pour un programme classique
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
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 :
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)
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
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.
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
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.
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.
|