3. Modèle OSI (Open System Interconnection)
en 7 couches
ENSA Fès –Y.I.K
3
Couche Protocoles
Application FTP, HTTP, SMTP, POP, SSH,TELNET,
IMAP ….
Présentation SSL,WEP,WPA, Kerberos
Session Ports
Transport TCP, UDP
Réseau IPv4, IPv6,ARP, IPX
Liaison 802.11,WiFi,ATM, Ethernet, ISDN
Physique Fibre, Câble, Radio …
4. Modèle OSI simplifié
ENSA Fès –Y.I.K
4
Couche Protocoles
Application FTP, HTTP, IMAP, POP …
Transport TCP, UDP …
Internet IPv4, IPv6, Ipsec,TCMP …
Liaison ARP, PPP, DSL, Ethernet
5. Couche transport
ENSA Fès –Y.I.K
5
Les deux couche qui nous intéressent seront :
UDP (User Datagram Protocol), RFC 768
TCP (Transmission Control Protocol), RFC 793
6. Couche transport
ENSA Fès –Y.I.K
6
La couche transport fournit un ou plusieurs services de
communication entre applications (par exemple TCP ou
UDP)
pour communiquer, ces applications doivent se connaître
il existe donc un mécanisme de nommage…
une application fournit un service particulier sur une
machine donnée
le service est identifié par un port
la machine est identifiée par une adresse
7. Couche transport
ENSA Fès –Y.I.K
7
un couple (adresse, port) est un point de
communication
toute communication ne peut s’effectuer qu’entre au
moins deux points de communications
l’émetteur
le (ou les) receveur(s)
Les ports sont utilisés pour assurer le multiplexage,
Les ports UDP et TCP sont distincts (deux espaces)
8. Couche transport
ENSA Fès –Y.I.K
8
Il existe essentiellement trois types de ports :
les numéros de port de 0 à 1 023 correspondent
aux ports "bien-connus" (well-known ports), utilisés
pour les services réseaux les plus courants.
les numéros de ports de 1 024 à 49 151
correspondent aux ports enregistrés (registered
ports), assignés par l'IANA (Internet Assigned
Numbers Authority)
les numéros de ports (libres) de 49 152 à 65 535
correspondent aux ports dynamiques, utilisables
pour tout type de requêtesTCP ou UDP
9. Couche transport
ENSA Fès –Y.I.K
9
Les ports reconnus (Well-known ports) sont utilisés
par des services réseau d’usage général et commun :
20 et 21 pour FTP
25 pour SMTP
80 pour HTTP
ce qui signifie que pour établir une connexion avec un
serveur web, il faut s’adresser au port 80 de la machine
concernée
11. Communication réseau : java.net
ENSA Fès –Y.I.K
11
Le paquetage java.net offre les moyens de
communication entre machines à travers les réseaux, et
notamment à travers Internet. Il offre :
la récupération et la manipulation des adresses Internet IP
grâce à la classe InetAddress,
les communications de bas niveau grâce aux classes
DatagramPacket et DatagramSocket,
les communications en mode connecté grâce aux classes
Socket et ServerSocket,
l’accès de type fichier désigné par URL grâce aux classes URL
et URLConnection.
12. Classe InetAddress
ENSA Fès –Y.I.K
12
La classe InetAddress fournit les méthodes :
getLocalHost() : retourne un objet qui contient l’adresse IP de
la machine locale.
getByName(String nom_de_la_machine) : retourne un objet
qui contient l’adresse IP de la machine dont le nom est passé
en paramètre.
getHostName(): retourne le nom de la machine dont l'adresse
est stockée dans l'objet.
getAddress(): retourne l'adresse IP stockée dans l'objet sous
forme d'un tableau de 4 octets
13. Exemple 1 :
ENSA Fès –Y.I.K
13
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Classe_tcp {
InetAddress localeAdresse;
InetAddress serveurAdresse;
public Classe_tcp() throws UnknownHostException {
localeAdresse = InetAddress.getLocalHost();
serveurAdresse = InetAddress.getByName("www.google.com");
System.out.println("L'adresse locale est : " + localeAdresse);
System.out.println("L'adresse du serveur de Google : " +
serveurAdresse);
}
14. Exemple 2 :
ENSA Fès –Y.I.K
14
public static void main(String[] args) throws UnknownHostException {
//Trouver l'addresse IP d'un domaine
String hostName = "www.ensaf.ac.ma";
String ip = InetAddress.getByName(hostName).getHostAddress();
System.out.println("ip de " + hostName + " est : " + ip);
//Trouver le nom de domaine de l'adresse IP
String ipAdresse1 = "212.217.0.1";
String ipAdresse2 = "212.217.1.1";
String hostName1 =
InetAddress.getByName(ipAdresse1).getHostName();
String hostName2 =
InetAddress.getByName(ipAdresse2).getHostName();
System.out.println("le nom de l'hote de l'IP : " + ipAdresse1 +
" est : " + hostName1);
System.out.println("le nom de l'hote de l'IP : " + ipAdresse2 +
" est : " + hostName2);
}
15. Communication de bas niveau :
DatagramPacket - UDP
ENSA Fès –Y.I.K
15
Il s’agit de transmission de paquets individuels, en mode
non connecté.
Ces transmissions sont peu fiables
Elles ne garantissent pas la réception des paquets
Et n’assurent pas que l’ordre d’arrivée soit le même que
l’ordre d’émission
Plus rapide mais moins fiable que TCP
Les paquets sont représentés par des objets de classe
DatagramPacket.
16. Communication de bas niveau
ENSA Fès –Y.I.K
16
Le constructeur DatagramPacket(byte[] buf, int long) crée un
objet destiné à recevoir un paquet.
Le constructeur DatagramPacket(byte[] buf, InetAddress adr,
int port) spécifie un paquet destiné à être émis vers le port du
site d’adresse adr.
class DatagramPacket {
DatagramPacket(byte[] buf, int long);
DatagramPacket(byte[] buf, InetAddress adr, int port);
inetAddress getAddress();
byte[] getData;
int getLength();
int getPort();
}
17. Communication de bas niveau
ENSA Fès –Y.I.K
17
Le constructeur DatagramSocket() crée une socket associé à
un numéro de port disponible décidé par le système.
Le constructeur DatagramSocket(int port) impose le numéro
de port indiqué.
class DatagramSocket {
DatagramSocket() throws SocketException;
DatagramSocket(int port) throws SocketException;
DatagramSocket(SocketAddress sa);
DatagramSocket(int port, InetAdress adresse);
int getLocalPort();
void send(DatagramPacket p);
void receive(DatagramPacket p);
}
18. DatagramSocket
ENSA Fès –Y.I.K
18
la classe DatagramSocket représente un point de
réception ou un point d’envoi
pour la réception d’un paquet, il est nécessaire d’attacher
la socket à un port donné sur une adresse (ou toutes) de
la machine
soit en construisant une socket attachée
soit en construisant une socket puis en l’attachant
les principaux constructeurs sont :
DatagramSocket(int port);
DatagramSocket(SocketAddress sa);
DatagramSocket(int port, InetAdress adresse);
19. DatagramSocket
ENSA Fès –Y.I.K
19
DatagramSocket(int port);
permet de construire une socket pour réception de paquets
attachée au port donné sur toutes les adresses de la machine
les autres constructeurs permettent de spécifier l’adresse de
l’attachement en particulier
l’attachement d’une socket non déjà attachée s’effectue par un
appel à :
void bind(SocketAddress adresse);
où la classe SocketAddress est abstraite; mais possède une
sous-classe concrète InetSocketAddress :
InetSocketAddress(int port);
InetSocketAddress(String nom, int port)
20. Communication de bas niveau
ENSA Fès –Y.I.K
20
La méthode getLocalPort() permet de connaitre le numéro du
port associé
La méthode send(DatagramPacket p) envoie le paquet p.
La méthode receive(DatagramPacket p) range le prochain
paquet reçu dans l’objet p.
class DatagramSocket {
DatagramSocket() throws SocketException;
DatagramSocket(int port) throws SocketException;
DatagramSocket(SocketAddress sa);
DatagramSocket(int port, InetAdress adresse);
int getLocalPort();
void send(DatagramPacket p);
void receive(DatagramPacket p);
}
21. Communications fiables en mode connecté
ENSA Fès –Y.I.K
21
La classe Socket définit un canal de transmission entre
machines.
Les communications entre les machines se font au moyen
de canaux d’entrées/sorties séquentielles de type
InputStream et OutputStream.
Le protocole de communication (TCP) garantit le respect
de l’ordre. class Socket {
Socket(String host, int port);
Socket(InetAddress adr, int port);
InetAddress getInetAddress();
InputStream getInputStream();
OutputStream getOutputStream();
void close();
}
23. Gérer les erreurs réseau
ENSA Fès –Y.I.K
23
Au moment de la réalisation des opérations réseaux, quatre
exceptions peuvent être capturées
1. La première exception que nous essayons de capturer est
l’exception UnknownHostException.
Il s’agit d’une sous-classe d’IOException.
Elle est levée afin d’indiquer que l’adresse IP d’un hôte ne peut
être déterminée.
NoRouteToHostException et ConnectException sont des
sous-classes de SocketException.
24. Gérer les erreurs réseau
ENSA Fès –Y.I.K
24
2. NoRouteToHostException
signale qu’une erreur s’est produite lors de la tentative de
connexion à un socket, à une adresse et un port distants.
En général, l’hôte distant ne peut pas être atteint en raison
d’un problème lié à un pare-feu ou un routeur interposé.
3. L’exception ConnectException
est levée si une connexion à l’hôte distant est refusée.
4. IOException
est une exception de portée plus générale qui peut
également être levée à partir d’appels réseau.
27. Contacter un serveur
ENSA Fès –Y.I.K
27
Pour se connecter à un serveur via TCP/TP, on utilise la
classe Java Socket.
Lors de la construction de l’instance socket, une
connexion de socket est opérée au serveur spécifié par
serverName sur le port désigné par le serveur, ici est 80.
A chaque fois qu’un Socket est créé, vous devez veiller à
fermer le socket lorsque vous avez terminé en appelant la
méthode close() sur l’instance Socket avec laquelle vous
travaillez.
String serveurName = "www.google.com";
Socket socket = new Socket(serveurName, 80);
28. Exemple : Socket
ENSA Fès –Y.I.K
28
import java.io.IOException;
import java.net.Socket;
public class Test {
public static void main(String[] args) throws IOException {
String serveurName = "www.google.com";
Socket socket = new Socket(serveurName, 80);
System.out.println(socket);
}
}
Résultat :
29. Se connecter à un serveur existant
ENSA Fès –Y.I.K
29
Pour se connecter en mode client/serveur, la classe
Socket ne suffit pas.
En général, l’établissement d’une connexion est toujours
dissymétrique :
Il y a un côté serveur, qui préexiste, dont l’adresse est
supposée connue, et qui attend des clients,
En un côté client qui a l’initiative de l’établissement de la
connexion.
Ceci nécessite une seconde sorte d’objet côté serveur, un
ServerSocket, dont le rôle est d’être à l’écoute des clients.
30. Les flux réseau en Java
ENSA Fès –Y.I.K
30
Le package à connaître est java.net
Deux clases importantes pour la connexion de type
Client/Serveur est :
Socket
Socket s = new Socket(String nom, int port);
ServerSocket
ServerSocket ss = new ServerSocket(numero_port);
class ServerSocket {
ServerSocket(int port);
InetAddress getInetAddress();
Socket accept();
void close();
}
31. Socket
ENSA Fès –Y.I.K
31
Le package java.net comprend la classe ServerSocket, qui met en
œuvre une sorte de prise serveur qu'on peut utiliser pour écouter
et accepter les connexions des clients:
ServerSocket ss = new ServerSocket(numero_port);
On obtient un objet de la classe ServerSocket sur un port spécifique
Le package java.net fournit aussi une classe Socket qui met en
œuvre une connexion bidirectionnelle entre le client (programme
Java) et un serveur (autre programme) situé sur le réseau. La
création d'un socket pour un programme client s'effectue à l'aide
d'un constructeur
Socket s = new Socket(String nom, int port);
Le nom correspond à l'identité du client de type InetAddress
Le port correspond au numéro de port sur lequel on veut se
connecter sur le serveur
32. Programme côté client
ENSA Fès –Y.I.K
32
import java.net.Socket;
public class Client {
public static final int PORT = 8090;
public static void main(String[] args) {
Socket socket = new Socket("localhost", PORT);
}
33. Shéma de la communication Client/Serveur
ENSA Fès –Y.I.K
33
34. Principe de base
ENSA Fès –Y.I.K
34
s:Socket
getOutputStream()
getInputStream()
s:Socket
getInputStream()
getOutputStream()
write
is
os
os
is
write
read
read
ss:ServerSocket
port = 8090
accept():Socket
Création d’un serveur :
Création d’un client :
InputStream is=s.getInputStream();
OutputStream os=s.getOutputStream();
int nb = is.read();
int rep = nb*2;
os.write(rep);
ServerSocket ss = new ServerSocket(8090);
Socket s = ss.accept();
String IP = "127.0.0.1";
Socket s = new Socket(IP, 8090);
InputStream is=s.getInputStream();
OutputStream os=s.getOutputStream();
os.write(100);
int rep = is.read();
System.out.println(rep);
35. ServerSocket
ENSA Fès –Y.I.K
35
ServerSocket(int port); créé une socket attachée au port
spécifié et permettant de contrôler les demandes de
connexion entrantes
la méthode Socket accept(); permet d’attendre une
demande de connexion entrante, de l’accepter lorsqu’elle
arrive et de fournir en retour une Socket de service
autorisant la communication
36. Programme côté serveur
ENSA Fès –Y.I.K
36
import java.net.ServerSocket;
import java.net.Socket;
public class Serveur {
public static final int PORT = 8090;
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Le ServerSocket est instancié avec le
port : " + serverSocket.getLocalPort());
System.out.println("Le ServerSocket utilise inetAdress : " +
serverSocket.getInetAddress());
System.out.println("Le ServerSocket utilise le
localSocketAdresse : " +
serverSocket.getLocalSocketAddress());
System.out.println("Le ServerSocket est instancié avec la un
buffer de taille : " + serverSocket.getReceiveBufferSize());
do {
Socket socket = serverSocket.accept();
} while (true);
serverSocket.close();
}
38. Exemple 1 : code source côté serveur (1/2)
ENSA Fès –Y.I.K
38
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Serveur {
static ServerSocket ss;
public static void main(String[] args) throws IOException {
ss = new ServerSocket(8888);
System.out.println("le port 8888 est ouvert. J'attends la
connexion d'un client");
39. Exemple : code source côté serveur (2/2)
ENSA Fès –Y.I.K
39
Socket clientSocket = ss.accept();
System.out.println("Nouveau client connecté");
System.out.println("Génération de l'objet InputStream et
OutputStream de la Socket");
System.out.println("-----------------------------------------");
InputStream is = clientSocket.getInputStream();
OutputStream os = clientSocket.getOutputStream();
System.out.println("J'attends un nombre (1 orctet)!");
int nb = is.read();
System.out.println("J'envoie la réponse");
os.write(nb*2);
System.out.println("Déconnexion du client");
clientSocket.close();
}
}
40. Exemple : code source côté client (1/2)
ENSA Fès –Y.I.K
40
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
static Socket clientSocket;
static Scanner clavier;
public static void main(String[] args) throws
UnknownHostException, IOException {
System.out.println("Créer une connexion au serveur: ");
clientSocket = new Socket("127.0.0.1", 8888);
41. Exemple : code source côté client (2/2)
ENSA Fès –Y.I.K
41
System.out.println("Génération de l'objet InputStream et
OutputStream de la Socket");
System.out.println("-----------------------------------------");
InputStream is = clientSocket.getInputStream();
OutputStream os = clientSocket.getOutputStream();
System.out.println("Lire un nombre au clavier NB = ");
clavier = new Scanner(System.in);
int nb = clavier.nextInt();
System.out.println("Envoyer le nomvrbe " + nb + " au serveur");
os.write(nb);
System.out.println("Attendre la réponse du serveur ");
int rep = is.read();
System.out.println("la réponse est : " + rep);
}
}
43. Lecture et écriture de socket
ENSA Fès –Y.I.K
43
InputStream getInputStream(); permet d’obtenir le flux de
lecture correspondant aux écritures du pair
OutputStream getOutputStream(); permet de récupérer
le flux d’écriture correspondant au flux de lecture du pair
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter out = new OutputStreamWriter(outputStream);
PrintWriter pw = new PrintWriter(out);
InputStream inputStream = socket.getInputStream();
InputStreamReader in = new InputStreamReader(inputStream);
BufferedReader bf = new BufferedReader(in);
44. Lire du texte
ENSA Fès –Y.I.K
44
Une fois l’instance socket obtenue, nous appelons la
méthode getInpuStream() pour obtenir une référence
au flux d’entrée du socket.
Avec cette référence, nous créons un InputStreamReader
et l’utilisons pour instancier un BufferedReader. Nous
lisons enfin le texte sur le réseau avec la méthode
readLine() du BufferedReader.
Socket socket = new Socket(serverName, 80);
InputStream is = socket.getInputStream();
InputStreamReader in = new InputStreamReader(is);
BufferedReader br = new BufferedReader(in);
String text = br.readLine();
45. Écrire du texte
ENSA Fès –Y.I.K
45
Une fois l’instance de socket obtenue, nous appelons la
méthode getOutputStream() pour obtenir une référence au
flux de sortie du socket.
Lorsque la référence est acquise, nous instancions un
PrintWriter afin d’écrire du texte sur le réseau vers le serveur
avec lequel nous sommes connectés.
Le second paramètre que nous passons au constructeur
PrintWriter définit l’option de purge automatique (autoFlush).
La valeur true amène les méthodes println(), printf() et
format() à vider automatiquement le tampon de sortie.
La méthode flush() utilisée pour forcer l’envoi des données sur
le réseau.
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
PrintWriter out = new PrintWriter(osw, true);
out.print(msg); out.flush();
46. Lire les données binaires
ENSA Fès –Y.I.K
46
Nous appelons la méthode getInputStream() de l’instance
de socket afin d’obtenir une référence au flux d’entrée du
socket.
En passant le flux d’entrée en paramètre, nous instancions
un DataInputStream, que nous pouvons utiliser pour lire
des données binaires sur le réseau.
Nous utilisons la méthode readUnsignedByte() pour lire
un unique octet non signé sur le réseau.
InputStream in = socket.getInputStream();
DataInputStream din = new DataInputStream(in);
din.readUnsignedByte();
47. Lire les données binaires
ENSA Fès –Y.I.K
47
Si le volume de données que vous lisez est important, il
est préférable d’encapsuler le flux d’entrée du socket
dans une instance BufferedInputStream :
DataInputStream possède bien d’autres méthodes pour
lire des données dans n’importe quel type de données
Java primitif, :
read(), readBoolean(), readByte(), readChar(), readDouble(),
readFloat(), readInt(), readLong(), readShort(),
readUnsignedByte() et readUnsignedShort().
InputStream in = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bis);
din.readUnsignedByte();
48. Écrire des données binaires
ENSA Fès –Y.I.K
48
nous appelons la méthode getOutputStream() de l’instance de
socket pour obtenir une référence au flux de sortie du socket.
Nous instancions ensuite un DataOutputStream, que nous pouvons
utiliser pour écrire des données binaires sur le réseau.
Nous utilisons la méthode write() pour écrire un tableau d’octets
sur le réseau. La méthode write() prend trois paramètres.
Le premier est un byte[] servant à récupérer les octets à partir desquels
écrire.
Le second définit un décalage dans le tableau d’octets servant à
déterminer la position à partir de laquelle l’écriture doit être effectuée.
Le troisième spécifie le nombre d’octets à écrire. (ex. 10 octets)
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
os.write(byteArray, 0, 10);
49. Écrire des données binaires
ENSA Fès –Y.I.K
49
Si le volume de données que vous écrivez est important, il
devient plus efficace d’encapsuler le flux de sortie du socket
dans une instance BufferedOutputStream,
DataOutputStream possède d’autres méthodes pour écrire
des données depuis n’importe quel type de données Java
primitif, dont les suivantes :
write(), writeBoolean(), writeByte(), writeBytes(), writeChar(),
writeChars(), writeDouble(), writeFloat(), writeInt(), writeLong() et
writeShort(). Pour plus de détails sur l’utilisation de ces méthodes de
la classe DataOutputStream,
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
os.write(byteArray, 0, 10);
50. Lire des données sérialisées
ENSA Fès –Y.I.K
50
Java permet de sérialiser les instances d’objet et de les
écrire dans un fichier ou sur un réseau.
nous appelons la méthode getInputStream() de l’instance
de socket afin d’obtenir une référence au flux d’entrée du
socket.
Avec cette référence, nous pouvons instancier un
ObjectInputStream.
InputStream in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
try { Object o = ois.readObject(); }
catch (ClassNotFoundException e) { e.printStackTrace(); }
51. Lire des données sérialisées
ENSA Fès –Y.I.K
51
La classe ObjectInputStream est utilisée pour désérialiser
des données et des objets primitifs précédemment écrits
en utilisant un ObjectOutputStream.
Nous utilisons la méthode readObject() de l’objet
ObjectInputStream pour lire un objet depuis le flux.
L’objet peut ensuite être transtypé en son type attendu.
Exemple de lecture d’un objet Date depuis le flux :
try {
Date aDate = (Date) ois.readObject();
}
catch (ClassNotFoundException e) { e.printStackTrace(); }
52. Thread - réseau
ENSA Fès –Y.I.K
52
Un thread désigne un « fil d’exécution » dans le programme;
c'est-à-dire une suite linéaire et continue d'instructions qui
sont exécutées séquentiellement les unes après les autres.
En fait, le langage Java est multi-thread, c'est-à-dire qu'il peut
faire cohabiter plusieurs fils d’exécution de façon
indépendante.
L’utilisation des threads est très fréquente dans la
programmation réseau.
Un client FTP peut :
télécharger plusieurs fichiers,
naviguer sur plusieurs serveurs en même temps,
chaque connexion étant gérée par un thread différent,
53. Thread - réseau
ENSA Fès –Y.I.K
53
également très utilisés dans les applications disposant
d'interfaces graphiques. Par exemple :
dans un traitement de texte, un thread s'occupe de ce que
saisit l'utilisateur,
un autre est en charge de détecter les fautes d'orthographe et
de grammaire,
un autre se charge de l'impression du document dans une
tâche de fond, etc.
Les programmes Java ont tous au moins un thread
d’exécution qui est démarré lorsque la méthode main()
qui lance le programme est invoquée.
De plus, la JVM peut générer des threads supplémentaires
pour faire tourner le ramasse-miettes en tâche de fond.