Programmation Socket en Java Cours sockets Université Paul Sabatier
Plan Un bon réflexe Les adresses IP en Java Sockets en mode flot La classe Socket La classe ServerSocket Communication via les Sockets Fermeture d une Socket Client Socket en mode flot Serveur Socket en mode flot Sockets en mode datagramme La classe DatagramSocket Communication via les Sockets Fermeture d une Socket Client Socket en mode datagramme Serveur Socket en mode datagramme 83
Un bon réflexe Usez et Abusez de l aide en ligne Java : http://java.sun.com Contient les classes Java : Les interfaces Les constructeurs Les méthodes de la classe Les classes filles et parent 84
Informations diverses Le principe est proche des sockets C L utilisation des fonctionnalités réseau de Java nécéssite l importation de java.net.ce_dont_vous_avez_besoin; 85
Les adresses IP en Java 1/4 Représentés par la classe java.net.inetaddress Contient 2 champs : hostname Stocke le nom de l hôte (ex: www.monsite.com) address Stocke l adresse IP de l hôte Pas de constructeurs publics. Pour créer une InetAddress, il faut utiliser une des méthodes suivantes : public static InetAddress getbyname(string nom_hote) public static InetAddress [] getallbyname(string nom_hote) public static InetAddress getlocalhost() 86
Les adresses IP en Java 2/4 public static InetAddress getbyname (String nom_hote) Cette méthode utilise le DNS pour renvoyer une instance de la classe InetAddress contenant l adresse IP de la machine dont le nom est passé en paramètre En cas d erreur, lève l exception UnknownHostException Exemple : InetAddress adr = InetAddress.getbyName( www.site.com ); 87
Les adresses IP en Java 3/4 public static InetAddress getbyname [] (String nom_hote) Renvoie toutes les adresses IP de la machine (dont le nom est passé en paramètre) En cas d erreur, lève l exception UnknownHostException public static InetAddress getlocalhost () Renvoie une instance de la classe InetAddress contenant l adresse IP de la machine locale En cas d erreur, lève l exception UnknownHostException Équivalent à : getbyname(null) getbyname("localhost") 88
Les adresses IP en Java 4/4 public String gethostname () Renvoie la chaine de caractères contenant le nom de la machine locale Renvoie l adresse IP de la machine si elle n a pas de nom public byte [] getaddress () Renvoie l adresse IP de la machine locale sous forme de tableau d octets rangés selon l ordre réseau Le premier octet contient l octet de poids fort de l adresse Remarque : La manipulation d octets non signés pose problème en Java car il n y a pas d équivalent au type C unsigned char. Les octets supérieurs à 127 sont donc traités comme des nombres négatifs! Pour récupérer les bonnes valeurs : int octetnonsigne = octet < 0? octet + 256 : octet; 89
Sockets en mode flot Utilisation de TCP (dans ce cours ) Principe : Création des sockets Positionnement des flux d entrée et de sortie Une fois les flux d entrée et de sortie liés, le principe est IDENTIQUE à : Une saisie au clavier pour la réception Un affichage à l écran pour l envoi On peut utiliser des méthodes standards! 90
Socket en mode flot (client) Création de la socket Attachement de la socket Construction de l adresse du serveur Si échec Demande de connexion Si OK Envoi/Réception de données via la socket Fermeture de la socket 91
La classe Socket 1/5 Socket en mode flot (TCP) Représente les sockets clients ou les sockets de service Constructeurs : public Socket (String hote, int port) throws UnknownHostException, IOException Crée un socket et tente de s y connecter. Lève les exceptions : UnkownHostException = si le nom de la machine est inconnu IOException = pour la plupart des autres raisons: L hôte refuse la connexion Problème de connexion Erreur de routage des paquets Paramètres : String hote = chaine de caractère contenant le nom de l hôte int port = port de destination (port auquel la socket doit se connecter) Exemple : Socket lasocket = new Socket( www.site.com ), 47); 92
La classe Socket 2/5 constructeurs suite public Socket (InetAddress addresse, int port) throws IOException Crée un socket et tente de s y connecter. Lève l exception IOException Paramètres : InetAddress adresse = InetAddress contenant l adresse de l hôte int port = port de destination (port auquel la socket doit se connecter) 93
La classe Socket 3/5 constructeurs suite public Socket(String hote, int port, InetAddress addresselocale, int portlocal) throws IOException Analogue au constructeur Socket(String hote, int port) Les deux derniers paramètres permettent de choisir l interface réseau (et le port) d où doit partir la connexion Lève l exception IOException Paramètres : String hote = chaine de caractère contenant le nom de l hôte int port = port de destination (port auquel la socket doit se connecter) InetAddress adresselocale = InetAddress contenant l adresse locale à partir de laquelle la connexion doit se faire int portlocal = port local (port à partir duquel la socket doit se connecter) 94
La classe Socket 4/5 constructeurs suite public Socket(InetAddress address, int port, InetAddress addresselocale, int portlocal) throws IOException Analogue au constructeur Socket(InetAddress address, int port) Les deux derniers paramètres permettent de choisir l interface réseau (et le port) d où doit partir la connexion Lève l exception IOException Paramètres : InetAddress adresse = InetAddress contenant l adresse de l hôte int port = port de destination (port auquel la socket doit se connecter) InetAddress adresselocale = InetAddress contenant l adresse locale à partir de laquelle la connexion doit se faire int portlocal = port local (port à partir duquel la socket doit se connecter) 95
La classe Socket 5/5 constructeurs suite protected Socket() Et protected Socket(SocketImpl impl) throws SocketException Constructeurs protégés Crée un socket MAIS ne tente pas de connexion Souvent employé pour implanter des sockets au comportement personnalisé (chiffrement, proxy ) 96
La classe Socket 6/8 méthodes Réception d un flux d information d une Socket Java TCP public InputStream getinputstream() throws IOException Cette méthode permet de récupérer le flux en provenance d une socket Il faut lier ce flux à un lecteur! Exemple InputStreamReader, BufferedReader Conseil : lier l InputStream à un flux offrant de meilleures fonctionnalités comme DataInputStream par exemple Exemple : DataInputStream flux_in = new DataInputStream(chaussette.getInputStream)); 97
La classe Socket 7/8 méthodes suite Envoi d informations dans une Socket Java TCP : public OutputStream getoutputstream() throws IOException Cette méthode permet de récupérer le flux en sortie vers une socket Il faut lier ce flux à un writer! Exemple PrintStream Conseil : lier l OutputStream à un flux offrant de meilleures fonctionnalités comme PrintStream par exemple Exemple : PrintStream flux_out = new PrintStream(chaussette.getOutputStream)); 98
La classe Socket 8/8 méthodes suite Fermeture de la Socket public void close() throws IOException Même si Java ferme les sockets à la fin du programme (ou via le Garbage collect), il est DE BON USAGE de fermer EXPLICITEMENT les socket via la méthode close. Valable pour tous les types de Sockets Sockets de service Sockets clients Sockets serveurs (ServerSockets) 99
Exemple de programme client (non complet) import java.io.*; import java.net.*; public class ClientEcho extends Object { public static void main (String args[]) { String reponse; Socket lesocket; PrintStream fluxsortiesocket; BufferedReader fluxentreesocket; try { // creation d une socket et connexion à la machine marine sur le port 7 lesocket = new Socket("marine.edu.ups-tlse.fr", 7); System.out.println("Connecté sur : "+lesocket); // création d un flux de type PrintStream lié au flux de sortie de la socket fluxsortiesocket = new PrintStream(leSocket.getOutputStream()); // creation d un flux BufferedReader lié au flux d entrée de la socket fluxentreesocket = new BufferedReader(new InputStreamReader(leSocket.getInputStream())); // envoi de données vers le serveur fluxsortiesocket.println("bonjour le monde!"); // attente puis réception de données du serveur reponse = fluxentreesocket.readline(); System.out.println("Reponse du serveur : " + reponse); lesocket.close(); } // try catch (UnknownHostException ex) { System.err.println("Machine inconnue : "+ex); ex.printstacktrace(); } catch (IOException ex) { System.err.println("Erreur : "+ex); ex.printstacktrace(); } } // main } // class 100
Socket en mode flot (serveur) Création de la socket Attachement de la socket d écoute Ouverture du service Attente d une demande de connexion et création d une socket de service ou Envoi/Réception de données via la socket de service Fermeture de la socket de service ou Fermeture de la socket d écoute 101
La classe ServerSocket 1/4 Représente les sockets serveurs (Sockets d écoute) Constructeurs : public ServerSocket (int port) throws IOException Crée un socket serveur qui attendra une connexion sur le port passé en paramètre Lève l exception IOException Notamment si le port choisi est déjà pris Ou si le port choisi est well-known (valeur < 1024) et vous n êtes pas super-utilisateur Paramètre : int port = port d écoute Si la valeur est 0, le système alloue dynamiquement le port (solution PEU conseillée pour un serveur) Exemple : ServerSocket s_serveur = new ServerSocket(47); 102
La classe ServerSocket 2/4 constructeurs suite public ServerSocket (int port, int taillefile) throws IOException Analogue au précédent Permet de préciser la longueur de la file d attente des requêtes de connexion Si la file est pleine et qu une connexion arrive, elle est refusée. Lève l exception IOException Notamment si le port choisi est déjà pris Ou si le port choisi est well-known (valeur < 1024) et vous n êtes pas super-utilisateur Paramètres : int port = port d écoute Si la valeur est 0, le système alloue dynamiquement le port (solution PEU conseillée pour un serveur) int taillefile = taille de la file d attente de connexions entrantes Par défaut fixé à 50 Plafonnée à la limite du système 103
La classe ServerSocket 3/4 constructeurs suite public ServerSocket (int port, int taillefile, InetAddress adresselocale) throws IOException Analogue au précédent Permet de préciser l adresse IP à laquelle attendre des connexions si la machine locale en possède plusieurs Lève l exception IOException Paramètres : int port = port d écoute Si la valeur est 0, le système alloue dynamiquement le port (solution PEU conseillée pour un serveur) int taillefile = taille de la file d attente de connexions entrantes InetAddress adresselocale = adresse IP où attendre les connexions Cette adresse doit appartenir à la machine locale 104
La classe ServerSocket 4/4 méthodes Accepter une connexion entrante public Socket accept() throws IOException Bloque l exécution du serveur dans l attente d une connexion entrante Renvoie un objet Socket lorsque la communication est établie Note : Pour ne pas bloquer l exécution du programme par le accept, le placer dans un thread spécifique Fermer la socket Identique à la méthode de la classe Socket 105
Exemple de programme serveur (non complet) import java.io.*; import java.net.*; public class ServeurEcho extends Object { public static void main (String args[]) { ServerSocket socketecoute; Socket socketservice; InputStream entreesocket; OutputStream sortiesocket; try { // création du socket d écoute (port numéro 7) socketecoute = new ServerSocket(7); while (true) { // attente d une demande de connexion socketservice = socketecoute.accept(); System.out.println("Nouvelle connexion : " + socketservice); // récupération des flux d entrée/sortie de la socket de service entreesocket = socketservice.getinputstream(); try { int b = 0; while (b!= -1) { b = entreesocket.read(); sortiesocket.write(b); } // while System.out.println("Fin de connexion"); } // try catch (IOException ex) { // fin de connexion System.out.println("Fin de connexion : "+ex); ex.printstacktrace(); } socketservice.close(); } // while (true) } // try catch (Exception ex) { // erreur de connexion System.err.println("Une erreur est survenue : "+ex); ex.printstacktrace(); } } // main } // class 106
EXERCICE : Écrire un programme client permettant d interroger un serveur daytime dont l adresse est fournie en paramètre Écrire un programme serveur de type daytime. 107
Sockets en mode datagramme (UDP) Chaque processus doit créer une socket et l utilise pour envoyer (ou attendre et recevoir) des données Manipulation de datagrammes Via les objets DatagramPacket 108
La classe DatagramSocket 1/2 Permet de créer et manipuler des sockets UDP Constructeurs : public DatagramSocket() throws SocketException Crée un socket UDP permettant l envoi et la réception de datagrammes. Lève l exception SocketException : Si il y a un problème de configuration réseau Un problème de port Attention : Avec ce constructeur, le système attribue lui-même le port 109
La classe DatagramSocket 2/2 Constructeurs : public DatagramSocket (int port) throws SocketException Analogue au précédent Permet de choisir le port UDP Lève l exception SocketException Paramètre : int port = port Si la valeur est 0, le système alloue dynamiquement le port public DatagramSocket (int port, InetAddress adresse) throws SocketException Analogue au précédent Mais permet en plus de choisir l adresse IP liée au port Lève l exception SocketException Paramètre : int port = port InetAddress adresse = adresse IP utilisée par la socket UDP 110
La classe DatagramPacket 1/3 Permet de manipuler les datagrammes échangés entre les correspondants Constructeurs : public DatagramPacket (byte[] tampon, int lg) Crée un objet employé pour la réception d un datagramme Paramètres : byte[] tampon = tableau d octets permettant la réception des données ATTENTION : Si la taille du tableau est insuffisante, les données seront tronquées int lg = taille du tableau (ou des données à recevoir) Exemple : byte[] tampon = new byte[1024]; DatagramPacket datagramme = new DatagramPacket(tampon, tampon.length); 111
La classe DatagramPacket 2/3 Constructeurs : public DatagramPacket (byte[] tampon, int lg, InetAddress adresse, int port) Crée un objet employé pour l envoi d un datagramme Paramètres : byte[] tampon = tableau d octets contenant les données à envoyer int lg = taille du tableau (ou des données à envoyer) InetAddress adresse = adresse où envoyer le datagramme int port = port de destination Exemple : String message = coucou!!! ; byte[] tampon = message.getbytes(); InetAddress adresse = InetAddress.getByName( moncorrepsondant.fr ); DatagramPacket datagramme = new DatagramPacket(tampon, tampon.length, adresse, 45848); 112
La classe DatagramPacket 3/3 Emission/Réception de datagrammes Méthodes : public void send (DatagramPacket p) throws IOException Envoie un datagramme passé en paramètre Lève l exception IOException en cas d erreur Paramètres : DatagramPacket p = datagramme prêt à l envoi public void receive (DatagramPacket p) throws IOException Attends la réception d un datagramme et remplie la datagramme passé en paramètre par les données reçues Lève l exception IOException en cas d erreur Paramètres : DatagramPacket p = datagramme «vide» prêt recevoir les données 113
Fermeture de la Socket UDP public void close() throws IOException Même si Java ferme les DatagramSocket à la fin du programme (ou via le Garbage collect), il est DE BON USAGE de fermer EXPLICITEMENT les DatagramSockets via la méthode close une fois qu ils ne sont plus utiles. 114
Exemple de programme d envoi de datagrammes (non complet) import java.net.*; import java.io.*; class EnvoiDatagramme { public static void main(string argv[]) throws SocketException, IOException, UnknownHostException { String message = "Bonjour le monde!"; byte[] tampon = ligne.getbytes(); InetAddress adresse = null; DatagramSocket socket; // recupère l adresse IP de la machine marine adresse = InetAddress.getByName("marine.edu.ups-tlse.fr"); // crée l objet qui stockera les données du datagramme à envoyer DatagramPacket envoi= new DatagramPacket(tampon,tampon.length,adresse,50000); // crée un socket UDP (le port est choisi par le système) socket=new DatagramSocket(); } } // envoie le datagramme UDP socket.send(envoi); 115
Exemple de programme de réception de datagrammes (non complet) import java.net.*; import java.io.*; class ReceptionDatagramme { public static void main(string argv[]) throws SocketException, IOException { byte[] tampon = new byte[1000]; String texte; } // crée un socket UDP qui attends des datagrammes sur le port 50000 DatagramSocket socket =new DatagramSocket(50000); // crée un objet pour stocker les données du datagramme attendu DatagramPacket reception = new DatagramPacket(tampon, tampon.length); // attends puis récupère les données du datagramme socket.receive(reception); // récupère la chaîne de caractère reçue // Note: reception.getlength() contient le nombre d octets reçus texte=new String(tampon, 0, reception.getlength()); System.out.println("Reception de la machine "+ reception.getaddress().gethostname()+" sur le port" +reception.getport() + " :\n"+texte ); } 116
EXERCICE : Écrire un programme client permettant d interroger un serveur daytime dont l adresse est fournie en paramètre Écrire un programme serveur de type daytime. 117