Programmation par Sockets. Sockets en Java. Andrey SADOVYKH [email protected] http://sadovykh.free.fr/cnam/ CNAM Réseaux C3 – 2005 - ©Andrey Sadovykh 2 Plan du cours Principes de Sockets Sockets en Java TD - Carnet d’Adresses partagé – Sockets TCP Principes de Sockets CNAM Réseaux C3 – 2005 - ©Andrey Sadovykh 4 Plans Principes de Sockets Définition de sockets Protocoles Internet TCP et UDP Format réseaux de données Sockets UDP Sockets TCP Problème de Blocage 5 Principes des sockets Socket == Fichier write() pour envoyer read() pour recevoir Client Server Donnes-moi la page Index.html ports ports yahoo.fr 80 HTTP 6 Définition des sockets Une socket = {une famille ; un mode de communication ; un protocole} Exemple de familles de sockets : Exemple de modes de communication : processus sur la même station Unix : sockets locales (AF_UNIX en C) processus sur des stations différentes à travers Internet : sockets Internet (AF_INET en C) Datagrames – ou mode non connecté Flux de données – ou mode connecté Etc. Exemple de protocoles de sockets : IP, UDP, TCP, … 7 Protocoles Internet Application AF_INET: UDP, TCP IP TCP: 1 2 3 4 1 Mode avec connexion: Envoie par séquences L’ordre d’envoie est respecté La livraison est garantie La perte de connexion est détecté 2 3 4 UDP: Ethernet 1 2 3 4 2 1 3 4 Mode sans connexion: Envoie par paquets Réception par des plusieurs destinataires est possible Ni livraison ni l’ordre de séquence ne sont pas garantis, même si la probabilité est 10-6 8 Format Réseau – Little / Big Endians short /* (2 Octets) */ long /* (8 Octets) */ Exemple: short n=3; /* 11 en binaire*/ Motorola Intel 00…0 0…11 0…11 00…0 host byte order Big Endians host byte order Little Endians Réseau 00…0 0…11 network byte order Big Endians Un des problèmes d’interopérabilité le plus connu. Les représentation de donnée sur chaque d’extrémités peuvent être différentes. En C, une conversion vers format réseau (network byte order) est nécessaire. 9 Sockets UDP Étapes d’utilisation de sockets lors de communication client-serveur en UDP : le serveur et le client ouvrent chacun une « socket » le serveur la nomme (il l’attache à un de ses ports (un port précis)) le client ne nomme pas sa socket (elle sera attachée automatiquement à un port lors de l’émission) le client et le serveur dialogue : write(…) et read(…) finalement toutes les sockets doivent être refermées Les deux extrémités n’établissent pas une connexion : elles ne mettent pas en oeuvre un protocole de maintien de connexion si le processus d’une extrémité meurt l’autre n’en sait rien ! 10 Étapes d’utilisation de sockets mode UDP: serveur reçoit les données Initialisation: Serveur Client socket () socket () bind() attribution d’un port Dialogue: read() write() Fermeture: close() close() 11 Sockets TCP Étapes d’utilisation de sockets lors de communication client-serveur en TCP : le serveur et le client ouvrent chacun une « socket » le serveur la nomme (il l’attache à un de ses ports (un port précis)) le client n’est pas obligé de la nommer (elle sera attachée automatiquement à un port lors de la connexion) le serveur écoute sa socket nommée le serveur attend des demandes de connexion le client connecte sa socket au serveur et à un de ses ports (précis) le serveur détecte la demande de connexion une nouvelle socket est ouverte automatiquement le client et le serveur dialogue sur la nouvelle socket (read, write) le serveur attendre de nouvelles demandes de connexions finalement toutes les sockets doivent être refermées 12 Étapes d’utilisation de sockets mode TCP: serveur reçoit les données Initialisation: Serveur Client socket () socket () bind() attribution d’un port listen() mode d’écoute Connexion: Dialogue: Fermeture: accept() connect () une nouvelle socket !!! read() write() Communication sur la nouvelle socket Communication sur la nouvelle socket close() close() 13 Problème de blocage Serveur Client socket () socket () bind() attribution d’un port listen() mode d’écoute Blocage: Blocage: accept() connect () read() write() Communication sur la nouvelle socket Communication sur la nouvelle socket close() close() 14 Solution: nouveau processus Processus Principal: Serveur: accept() Processus Secondaires: Traitement de communication une nouvelle socket !!! while(…) fork() … socket1 read() send() … socket2 read() send() … Client1 données données Client2 15 Sockets TCP non bloquant Étapes d’utilisation de sockets lors de communication client-serveur en TCP : le serveur et le client ouvrent chacun une « socket » le serveur la nomme (il l’attache à un de ses ports (un port précis)) le client n’est pas obligé de la nommer (elle sera attachée automatiquement à un port lors de la connexion) le serveur écoute sa socket nommée le serveur attend des demandes de connexion le client connecte sa socket au serveur et à un de ses ports (précis) le serveur détecte la demande de connexion une nouvelle socket est ouverte automatiquement le serveur crée un processus pour dialoguer avec le client le nouveau processus continue le dialogue sur la nouvelle socket le serveur attende en parallèle de nouvelles demandes de connexions finalement toutes les sockets doivent être refermées Programmation par sockets en Java CNAM Réseaux C3 – 2005 - ©Andrey Sadovykh 17 Plan Les prérequis: Flux de données Java Sockets TCP Sérialisation Préparation de données Optionnellement: Threads Serveur TCP nonbloquant (voir les support ) Spécificités Sockets UDP en Java Sockets TCP en Java 18 Pré requis java.io - les entrées-sorties (pp. 72-80) java.io.File – opérations sur les fichiers (pp. 8183) InputStream / OutputStream – flux et opérations sur les flux de données BufferedInputStream/BufferedOutputStream DataInputStream/DataOutputStream FileInputStream / FileOutputStream (voir les corrections) Sérialisation (pp. 97-102) Interface java.io.Serializable (voir les corrections) ObjectInputStream/ObjectOutputStream (voir les corrections) 19 Spécificités Il existe toujours des socket UDP et TCP Les sockets TCP doivent être associées à des « flux » (in et out) Les principes sont les mêmes Les sockets sont des objets (bien sur!) facilité de lecture et d’écriture Certaines opérations sont devenues implicites De nouvelles opérations sur des « flux » apparaissent Bibliothèque java.net.* 20 Spécificités: Initialisation client UDP TCP serveur client serveur DatagramSocket() DatagramSocket(port) Socket(ServerName, ServerPort) ServerSocket(port) 21 Sockets UDP en Java class DatagramSocket : (coté client et coté serveur) Constructeur : Méthodes : DatagramSocket() : creation d’une socket UDP, libre close() : ferme la socket. receive(DatagramPacket p) : reçoit un « DatagramPacket » de cette socket. send(DatagramPacket p) : envoit un « DatagramPacket » sur cette socket. class DatagramPacket : Constructeur : DatagramPacket(byte[] buf, int InetAddress address,int port) : creation d’un packet à destination d’une machine et d’un port spécifiés … 22 Sockets TCP en Java (client) class Socket : (coté client, et coté serveur en partie) Constructeur : connect() est implicite Méthodes : Socket(String host, int port) : creation d’une socket TCP connectée sur le port et la machine hôte spécifiés. close() : ferme la socket. OutputStream getOutputStream() : revoie un flux de sortie pour cette socket. IntputStream getIntputStream() :revoie un flux d’entrée pour cette socket. class OutputStream : Méthodes : write(byte[] buffer) : écrit dans le flux. close() : ferme flux. class InputStream : Méthodes : read(byte[] buffer) : lit le flux. close() : ferme flux. 23 Sockets TCP en Java (serveur) class ServerSocket : (coté serveur) Constructeur : bind() est implicite ServerSocket(int port) : creation d’une socket TCP connectée sur le port spécifié de la machine hôte. Méthodes : close() : ferme la socket. OutputStream getOutputStream() : revoie un flux de sortie pour cette socket. IntputStream getIntputStream() : revoie un flux d’entrée pour cette socket. Socket accept() : écoute la socket et attend une requête de connection, retourne une nouvelle socket sur laquelle écouter le nouveau client (et lui seul) listen() est implicite Exemple – Sockets en Java CNAM Réseaux C3 – 2005 - ©Andrey Sadovykh 25 Développement d’une application socket – une approche Définition d’un protocole d’application 1. 2. 3. Définition d’opérations (fonctions) Définition de messages d’entrée et de sorti, qui sont associés aux opérations Définition de tailles des messages Définition de moyennes de distinction des messages (codes de message, port différant, …) Implémentation de sérialisation/dessérialisation des messages. Déploiement des mécanismes réseaux (sockets) Exemple : Server Echo TCP. 1 opération Description : Client envoie une chaîne de caractères au Serveur. Serveur la renvoie en y ajoutant « C’est l’écho ». Opérations : Echo Message d’entrée - String echoString de taille variable, ce que nécessite envoie de taille actuelle avant de chaque message. Message de sortie – String reponse = « C’est l’écho :» + echoString 26 taille variable, ce que nécessite envoie de taille actuelle avant de chaque message. Distinction de messages : Pas nécessaire, car un seul messages d’entrée et un seul message de sortie sont possible. De plus, opération est la seule. Sérialisation : OutputByteStream obs = new OutputByteStream (); obs. write (echoString.getBytes()); Dessérialisation : InputByteStream ibs = new InputByteStream (); Ibs. read(echoString.getBytes()); Exemple : Implantation socket coté Serveur Serveur: ouvre port 8080 ServerSocket server = new ServerSocket (8080); attend une connexion; Socket nouvelleSocket = server.accept(); lit une chaîne de caractères; InputStream fluxEntree = nouvelleSocket.getInputStream(); byte taille [] = new byte[1]; fluxEntree.read(taille); byte buffer [] = new byte [taille[0]]; fluxEntree.read(buffer); renvoie cette chaîne en y ajoutant « C’est l’écho ». String echo = "C'est l'echo:"+ new String (buffer); OutputStream fluxSortie = nouvelleSocket.getOutputStream(); byte taille2 = (byte) echo.getBytes().length; fluxSortie.write(taille2); fluxSortie.write(echo.getBytes()); ferme toutes les connexions nouvelleSocket.close(); server.close(); 27 Exemple : Implantation socket coté Client Client Crée une connexion avec Serveur Socket client = new Socket (« localhost »,8080); Envoie une chaîne de caractères String request = "Salut!"; byte taille = (byte)request.getBytes().length; OutputStream fluxSortie = client.getOutputStream(); fluxSortie.write(taille); fluxSortie.write(request.getBytes()); Reçoit une chaîne de caractères InputStream fluxEntree = client.getInputStream(); byte [] taille2 = new byte[1]; fluxEntree.read(taille2); byte [] buffer = new byte [taille2[0]]; fluxEntree.read(buffer); Ferme toutes la connexions client.close(); 28 29 Exemple : Source Serveur import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { public static void main(String[] args) { try { // nouvelle socket sur le port 8080 ServerSocket server = new ServerSocket(8080); System.out.println("Serveur est demarre..."); // accepter les demandes de connexion Socket nouvelleSocket=server.accept(); // lire les donnees InputStream fluxEntree = nouvelleSocket.getInputStream(); byte taille [] = new byte[1]; fluxEntree.read(taille); byte buffer [] = new byte [taille[0]]; fluxEntree.read(buffer); System.out.println("Echo request:"+new String(buffer)); // preparer la reponse String echo = "C'est l'echo:"+ new String (buffer); // ecrire les donnee OutputStream fluxSortie = nouvelleSocket.getOutputStream(); byte taille2 = (byte) echo.getBytes().length; fluxSortie.write(taille2); fluxSortie.write(echo.getBytes()); // fermer nouvelleSocket nouvelleSocket.close(); // fermer socket principale server.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 30 Exemple : Source Client import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class EchoClient { public static void main(String[] args) { try { // creer et connecter une Socket cliente Socket client = new Socket ("localhost",8080); // ecire les donnees String request = "Salut!"; byte taille = (byte)request.getBytes().length; OutputStream fluxSortie = client.getOutputStream(); fluxSortie.write(taille); fluxSortie.write(request.getBytes()); // lire InputStream fluxEntree = client.getInputStream(); byte [] taille2 = new byte[1]; fluxEntree.read(taille2); byte [] buffer = new byte [taille2[0]]; fluxEntree.read(buffer); System.out.println("Response:"+new String(buffer)); // fermer socket cliente client.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Complément : Sérialisation en Java – Puissance de Java CNAM Réseaux C3 – 2005 - ©Andrey Sadovykh 32 Principe Java défini une interface java.io.Serializable pour rendre les objet sérialisable Il suffit que votre classe à sérialiser implante java.io.Serializable, car tous les types est presque toutes les classe de bibliothèques Java sont sérialisable. Utilisez ObjectOutputStream.writeObject(Object votreObjetSerializable) pour écrier dans le flux sortant. et ObjectInputStream.readObject(Object obj) pour lire le flux entrant. Attention Interopérabilité : Cette approche n’est que utilisable si les deux extrémités sont des Applications Java 33 Utilité pour les sockets !!! La transmission de la taille d’un Objet est géré automatiquement. Lecture: Récupérez le flux d’entrée InputStream socketInput =mySocket.getInputStream(); Convertissez le en un flux d’Objet ObjectInputStream myStream = new ObjectInputStream (socketInput ); Lisez votre Objet MyClass myObj = new MyClasse(); myObj = (MyClasse) myStream.readObject(); Voir ExempleSocket2 34 Exemple 2: Source Serveur import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { public static void main(String[] args) { try { // nouvelle socket sur le port 8080 ServerSocket server = new ServerSocket(8080); System.out.println("Serveur est demarre..."); // accepter les demandes de connexion Socket nouvelleSocket=server.accept(); // lire les donnees InputStream is = nouvelleSocket.getInputStream(); ObjectInputStream fluxEntree= new ObjectInputStream(is); String request; request=(String)fluxEntree.readObject(); System.out.println("Echo request:"+request); String echo = "C'est l'echo:"+ request; // ecrire les donnee OutputStream os = nouvelleSocket.getOutputStream(); ObjectOutputStream fluxSortie = new ObjectOutputStream(os); fluxSortie.writeObject(echo); // fermer nouvelleSocket nouvelleSocket.close(); // fermer socket principale server.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 35 Exemple 2: Source Client import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; public class EchoClient { public static void main(String[] args) { try { // creer et connecter une Socket cliente Socket client = new Socket("localhost", 8080); // ecire les donnees String request = "Salut!"; OutputStream os = client.getOutputStream(); ObjectOutputStream fluxSortie = new ObjectOutputStream(os); fluxSortie.writeObject(request); // lire les donnes String response; InputStream is = client.getInputStream(); ObjectInputStream fluxEntree = new ObjectInputStream(is); response = (String) fluxEntree.readObject(); System.out.println("Response:" + response); // fermer socket cliente client.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }