TP Programmation Réseau en Java
Annexe 1
Adresses Internet et URLs
Dans les TPs précédents nous avons parlé succinctement des adresses Internet et de leur manipulation avec Java. Nous allons détailler ici la classe InternetAddress qui permet de gérer les adresses IP.
Une machine (appelée aussi hôte ou host) est identifiée dans l’Internet par son adresse. L’adresse Internet d’une machine correspond à un numéro qui est unique dans le monde.
Pour des raisons mnémoniques, il est possible de donner un nom à une machine (ex : Toto, Garonne, Mimosa...). Certains hôtes ont plusieurs noms. Ce nom est géré de façon hiérarchique par le DNS (Système de Noms de Domaines).
L’adresse utilisée par la version actuelle du protocole IP (adresse IP), comporte deux champs: le champ adresse réseau (Network) dans l’Internet et le champ adresse hôte (Host) dans le réseau. Sa taille est de 4 octets (32 bits). Elle est souvent donnée en notation décimale pointée (ex: 127.95.35.54).
Comme l’adresse IP contient l’adresse réseau, une station changeant de réseau change d’adresse. D’autre part, une station multidomiciliée (qui dispose de plusieurs interfaces réseau) ou un routeur ont plusieurs adresses.
Il existe actuellement cinq classes d’adresses IP. Les trois premières permettent de gérer des réseaux de tailles diverses (il est à noter que la première classe n’est quasiment pas utilisée). La classe D permet de gérer une communication multipoint (un message est envoyé à plusieurs machines à la fois). La classe E est réservée et ne sera probablement jamais utilisée puisqu’on devrait bientôt migrer vers la nouvelle version d’IP IPv6 qui stockera les adresses IP dans 16 octets.
Figure 1 : Les classes d’adresses IP
La classe java.net.InetAddress permet de représenter les adresses Internet. Chaque objet de cette classe possède deux champs hostName et address contenant respectivement une chaîne de caractère et un tableau d’octets.
Le champ hostName stocke le plus souvent le nom de l’hote (www.irit.fr par exemple) et le champ address l’adresse IP.
Cette classe ne possède pas de constructeur publics. Pour créer un objet de type InetAddress il faut donc utiliser l’une des méthodes suivantes :
public static InetAddress getByName (String nom_hote)
public static InetAddress [ ] getAllByName (String nom_hote)
public static InetAddress getLocalHost ()
Cette méthode utilise le DNS pour renvoyer une instance de la classe InetAddress représentant l'adresse Internet de la machine de nom nom_hote. Voici un exemple d’utilisation (en supposant que la classe java.net.InetAddress a été précédement importée) :
InetAddress adr = InetAddress.getByName("www.irit.fr");
Lorsque la recherche DNS n'aboutit pas, une exception UnknownHostException est levée.
Exercice : Sachant que InetAddress (comme la plupart des classes Java) surcharge la méthode toString(), écrivez un programme créant un objet InetAddress et l'affichant.
Testez le programme avec divers noms de machines.
Donnez une adresse IP en lieu et place du nom de machine. Que se passe-t-il ?
Cette méthode renvoie toutes les adresses Internet de la machine de nom nom_hote.
Exercice : modifiez le programme précédent pour récupérer toutes les adresses d'une machine donnée.
Essayez de trouver une machine disposant de plusieurs adresses IP.
Renvoie une instance de la classe InetAddress représentant l'adresse Internet de la machine locale. Très pratique pour tester sur une même machine les programmes client et serveur. Equivalent à getByName (null) ou getByName ("localhost").
Exercice : modifiez le programme précédent pour afficher en plus l'adresse IP de la machine courante.
Renvoie le nom de la machine hôte, ou bien l'adresse IP si la machine n'a pas de nom.
Renvoie l'adresse IP stockée par une instance de la classe InetAddress sous la forme d'un tableau d'octets rangés dans l'ordre standard du réseau (network byte order). Ainsi l'octet d'indice 0 contient l'octet de poids fort de l'adresse.
La longueur du tableau retourné est actuellement 4 dans la plupart des cas (IPv4) mais devrait passer à 16 lorsque les adresses IP sur 128 bits auront cours (IPv6).
Exercice : tentez d'afficher à l'aide de votre programme les adresses IP renvoyées par cette méthode. Que remarquez vous ?
Remarque : la manipulation d'octets non signés pose des problèmes en Java car il n'y a pas d'équivalent au type C unsigned char. Ainsi, les octets supérieurs à 127 sont traités comme des nombres négatifs.
Pour récupérer les bonnes valeurs il convient de procéder comme suit :
int octetNonSigne = octet < 0 ? octet + 256 : octet;
Exercice : Corrigez votre programme pour afficher correctement les adresses IP renvoyées par getAddress().
public int hashCode ()
public boolean equals (Object obj)
public String toString ()
Ces méthodes surchargent celles de la classe Object, pour renvoyer un code de hashing, comparer un objet de classe InetAddress à un objet ou renvoyer une chaîne de caractères décrivant une adresse Internet.
Remarque importante : la première méthode est directement utilisée par la classe InetAddress qui contient une HashTable en membre statique. Ainsi, une adresse requise plusieurs fois sera immédiatement extraite du cache et donc obtenue beaucoup plus rapidement que par l'envoi d'une requête au serveur DNS.
Java permet, très simplement, d'accéder à un fichier ou à une ressource sur le réseau grâce à son URL (Uniform Resource Locator).
Contrairement au chemin d'accès classique à un fichier dont la notation varie d'un système à l'autre (c:\fichier.txt, /usr/unCompte/fichier.txt), une URL permet de désigner un fichier ou une ressource de manière uniforme quelque que soit le système qui héberge ce fichier.
Exemples d'URL :
http://www.javasoft.com/index.html,
http://www.eteks.com/coursjava/net10.html#AccesURL
De quoi est composée une URL ?
Une URL peut représenter un fichier mais aussi de manière plus générale une ressource. Par exemple, une ressource peut être un programme renvoyant une image ou le résultat d'un accès à une base de données. La plupart des programmes auxquels on accède sur un site Internet via une URL utilise le modèle CGI (Common Gateway Interface). Ce modèle définit comment appeler un programme et lui transmettre ses paramètres, de manière standard.
Par exemple, http://www.hit-parade.com/hp.asp?site=a15740 est un programme CGI appelé avec la valeur a15740 pour le paramètre site. Ce programme renvoie l'image du site hit-parade.com.
Java permet d'accéder au fichier ou à la ressource représentés par une URL sous forme de flux de données, grâce aux deux classes URL et URLConnection.
Cette classe permet de manipuler une URL. Les constructeurs de cette classe pouvant éventuellement déclencher une exception de type MalformedURLException, la création d'une nouvelle instance de classe URL doit être programmée dans un bloc try ... catch. L'objet créé ne garantit pas que le fichier existe mais seulement que l'URL mémorisée par l'objet est correctement formée et que le protocole spécifié est géré par la Machine Virtuelle Java.
Les objets de cette classe sont utilisés pour accéder sous forme de flux de données au fichier correspondant, mais aussi par certaines méthodes de la classe Applet pour obtenir l'URL d'un document HTML, lire une image ou un fichier son.
public URL (String spec) throws MalformedURLException
Construit une instance de la classe URL à partir de la chaîne de caractères spec représentant l'URL.
public URL (String protocol, String host, int port, String file) throws MalformedURLException
public URL (String protocol, String host, String file) throws MalformedURLException
Ces constructeurs permettent de créer un objet de classe URL à partir du protocole protocol, l'hôte host, le port port et le chemin d'accès file d'une URL.
Remarque : il ne faut pas oublier de commencer la chaîne file par le caractère "/" en effet cette chaîne représente le chemin absolu vers le fichier ou le répertoire pointé par l'URL.
Le second constructeur ne permet pas de préciser le numéro de port et c'est donc le port par défaut du protocole considéré qui sera visé par l'URL (80 pour http).
public URL (URL context, String spec) throws MalformedURLException
Construit une instance de la classe URL à partir d'une URL absolue existante context et de la chaîne de caractères spec. Si spec décrit entièrement une URL (avec protocole, hôte, fichier,...) , l'URL context est ignorée et l'objet créé correspond à l'URL spec. Sinon, context est utilisé comme URL de base qui sera complétée par les informations fournies dans spec, pour construire le nouvel objet de classe URL (spec peut par exemple désigner un fichier dans un sous répertoire différent).
Exemple :
URL u1 = new URL("http://www.macfaq.com/index.html");
URL u2 = new URL(u1, "vendor.html");
// u2 sera égal à http://www.macfaq.com/vendor.html
public String getProtocol ()
public String getHost ()
public int getPort ()
public String getFile ()
public String getRef ()
Ces méthodes permettent de fractionner un URL en récupérant : le protocole, l'hôte, le port, le chemin d'accès au fichier et la référence (appelée aussi ancre). Si le port n'a pas été précisé en paramètre du constructeur, la valeur -1 est renvoyée.
Exercice : Ecrivez un programme qui lit une URL sous la forme d'une chaîne de caractère, l'analyse pour savoir si elle est correcte syntaxiquement et la fractionne en affichant les différentes parties de l'URL.
Testez votre programme avec des URL référençant différents protocoles. Quels sont les protocoles reconnus par votre machine Java ?
public boolean sameFile (URL other)
Renvoie true si other désigne la même URL que l'objet sur lequel est invoquée cette méthode. Les références mémorisées par les objets ne sont pas prises en compte pour la comparaison. Plus gênant, les noms d'hôtes synonymes ne sont pas pris en compte et les URLs suivantes seront considérées comme différentes :
http://www.irit.fr et http://www.irit.fr:80 alors quelles représentent toutes les deux la racine d'un même serveur web.
public String toExternalForm ()
Renvoie une chaîne de caractères correspondant à l'URL mémorisée par un objet de classe URL.
public final InputStream openStream () throws IOException
Après s'être connecté à la ressource référencée par l'URL, cette méthode prend en charge la procédure d'authentification entre le client et le serveur puis ouvre un InputStream. Ce dernier extrait les données brutes (non interprétées) contenues dans le fichier désigné par l'URL : données ASCII d'un fichier texte, code HTML d'une page HTML, données binaires d'une image… Les informations liées au protocole (en-têtes HTTP par exemple) n'y figurent pas et il faudra faire appel à la méthode openConnection si l'on veut y accéder.
Exercice : modifiez le programme précédent pour afficher sous forme texte le contenu de l'URL fractionnée.
Tentez de récupérer une image avec ce programme.
public final Object getContent () throws IOException
Renvoie un objet correspondant au contenu du fichier représenté par un objet de classe URL : InputStream pour dans le cas d'un fichier ASCII ou HTML, URLImageSource dans le cas d'une image Gif ou JPEG. Si le type du fichier est inconnu null sera retourné.
Exercice : modifiez le programme précédent pour être sûr d'afficher du texte.
public URLConnection openConnection () throws IOException
Ouvre une connexion avec une URL, et renvoie une instance de la classe URLConnection qui permet d'obtenir toute sorte de renseignements (dates, en-tête,...) sur le fichier correspondant à l'URL.
public int hashCode ()
public boolean equals (Object obj)
public String toString ()
Ces méthodes surchargent celles de la classe Object, pour renvoyer un code de hashing, comparer un objet de classe URL à un objet ou renvoyer une chaîne de caractères correspondant à l'URL. equals utilisant la méthode sameFile, elle souffre donc des mêmes limitations.
public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
throws SecurityException
Si le gestionnaire de sécurité l'autorise, cette méthode initialise l'URLStreamHandlerFactory de l'application et renvoie une erreur (Error) si l'initialisation a déjà eu lieu. L'URLStreamHandler est chargé d'analyser l'URL puis de créer l'objet URLConnection adéquat afin de gérer la connexion sur le serveur. Ces opérations s'effectuent en coulisses et il est préférable de ne pas s'en préoccuper à moins que vous n'élaboriez votre propre client.
Ces deux classes contiennent chacune une méthode utilitaire permettant d'encoder et de décoder certaines parties d'une URL. En effet les URLs ne permettent pas l'utilisation d'espaces et de certains caractères (lettres accentuées et # par exemple). Ces classes sont surtout utilisées pour encoder la partie référence d'une URL, par exemple dans le cas où cette référence est utilisée pour passer des arguments à un script CGI.
URLEncoder :
public static String encode(String s)
URLDecoder :
public static String decode(String s) throws Exception
La procédure d'encodage est la suivante :
Il est important de noter que si cet encodage, appelé x-www-form-urlencoded, peut être utilisé tel quel pour fournir des données (par exemple issues d'un formulaire) aux scripts CGI, ce n'est pas le cas pour la partie nom de fichier d'une URL qui accepte les caractères '/' mais pas les caractères '+' utilisés pour remplacer les espaces dans ce cas il conviendra de traiter chaque nom de fichier ou de répertoire indépendamment et de remplacer ensuite les '+' (issus de la transformation des espaces) par %20 (% suivi du code ASCII représentant l'espace).
Ainsi l'URL correspondant au répertoire Windows :
"/Program Files/Microsoft Office/Modèles/Lettres et télécopies"
devra s'écrire :
"file://C:/Program%20Files/Microsoft%20Office/Mod%E8les/Lettres%20et%20t%E9l%E9copies/".
Exercice : écrivez un programme qui à partir d'un nom de fichier absolu génère l'URL correcte correspondante.
Cette classe abstraite gère la connexion avec une URL. Une instance d'une classe dérivant de cette classe peut être obtenue grâce à la méthode openConnection() de la classe URL.
Les méthodes de cette classe permettent de créer un flux de données pour lire et/ou d'écrire dans le fichier désigné par une URL, mais aussi d'obtenir toute sorte d'information sur ce fichier (sa date de dernière modification, sa taille, son type,...).
public abstract void connect () throws IOException
Les classes dérivées de la classe URLConnection doivent implémenter cette méthode pour réaliser la connexion avec une URL.
public Object getContent () throws IOException
Renvoie un objet correspondant au contenu du fichier. Cette méthode est identique à celle de la classe URL. En fait la classe URL ne fait qu’appeler la méthode de URLConnection.
public InputStream getInputStream () throws IOException
Cette méthode renvoie un flux de données en lecture à partir d'une connexion à une URL. Une exception de classe UnknownServiceException (dérivant de la classe IOException) est déclenchée si le protocole interdit l'accès en lecture à cette URL. Cette méthode est identique à la méthode openStream() de la classe URL. En fait la classe URL ne fait qu’appeler la méthode de URLConnection.
public OutputStream getOutputStream () throws IOException
Cette méthode renvoie un flux de données en écriture à partir d'une connexion à une URL. Une exception de classe UnknownServiceException (dérivant de la classe IOException) est déclenchée si le protocole interdit l'accès en écriture à cette URL.
Cette méthode peut, par exemple, être utilisée pour transmettre des données à un serveur Web lors d’une requête de type POST.
Il faudra au préalable appeler setDoOutput(true) car les URLConnection ne permettent pas par défaut de transférer des données vers le serveur.
public String getContentType ()
Renvoie le type MIME des données (text/html, text/plain, image/gif, image/jpeg…) ou null si ce renseignement n’est pas renvoyé par le serveur.
public int getContentLength()
Indique le nombre d’octets du contenu récupéré ou -1 si cette taille n'est pas donnée. Cette information est souvent incluse lors d’un transfert de données binaires et plus rarement pour des données textuelles.
public String getContentEncoding ()
Renvoie le type d’encodage subit par le contenu renvoyé ou null si ce renseignement n’est pas fourni par le serveur ou s’il n’y a pas eu d’encodage. Les types d’encodages les plus répandus sont Base-64 et quoted-printable mais ils sont peu utilisés sur le web.
public long getDate ()
public long getLastModified ()
public long getExpiration ()
Renvoie la date à laquelle le fichier a été envoyé, sa date de dernière modification et sa date d'expiration ou 0 si ces renseignements ne sont pas connus. Ces dates sont communiquées sous la forme d’un entier long donnant le nombre de secondes écoulées depuis le 1er Janvier 1970 à minuit GMT. Cette valeur peut ensuite être convertie en java.util.Date ainsi :
Date date = new Date(connexion.getDate()) ;
La date d’expiration indique la limite de validité du fichier. Ce qui signifie que si ce fichier est placé dans un cache il faudra le relire à cette date. Si ce renseignement est absent, ce qui est souvent le cas, getExpiration() renvoie 0, soit " le 1er Janvier 1970 à minuit GMT ", ce qui signifie dans ce cas que le fichier peut rester indéfiniment dans le cache.
Exercice : modifiez le programme récupérant le contenu d’une URL pour afficher d’abord les entêtes MIME standard.
public String getHeaderField (String name)
public int getHeaderFieldInt (String name, int default)
public long getHeaderFieldDate (String name, long default)
public String getHeaderFieldKey (int n)
public String getHeaderField (int n)
Ces méthodes permettent d’accéder aux informations indiquées dans les autres champs d’un en-tête MIME.
public URL getURL()
Renvoie l'URL avec laquelle la connexion est faite.
public boolean getDoInput ()
public boolean getDoOutput ()
public boolean getUseCaches ()
public boolean getAllowUserInteraction ()
Ces méthodes renvoient true, s'il est possible de lire ou d'écrire sur une connexion, si la connexion utilise le cache ou si elle autorise d'interagir avec l'utilisateur (pour lui demander par exemple un mot de passe). Par défaut, une connexion est ouverte en lecture.
public void setDoInput (boolean doinput)
public void setDoOutput (boolean dooutput)
public void setUseCaches (boolean usecaches)
public void setAllowUserInteraction (boolean allowuserinteraction)
Ces méthodes permettent d'autoriser l'accès en lecture ou en écriture à un fichier, l'utilisation du cache et l’interaction avec un utilisateur. La dernière méthode ne peut pas être appelée quand la connexion est déjà ouverte. Si c’est le cas, une IllegalAccessError est renvoyée (et non une IllegalAccessException!). Les programmes traitent en général les exceptions mais pas les erreur qui conduisent en général à l’arrêt du programme.
public boolean getDefaultUseCaches ()
public void setDefaultUseCaches (boolean defaultusecaches)
public static boolean getDefaultAllowUserInteraction ()
public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction)
Ces méthodes permettent de choisir le comportement par défaut des connexions au sujet de l’utilisation ou non d’un cache et de l’interaction avec l’utilisateur.
public void setIfModifiedSince (long ifmodifiedsince)
public long getIfModifiedSince ()
Certains protocoles permettent d’éviter la récupération d’un fichier si il n’a pas été modifié depuis une certaine date. Ces méthodes permettent de préciser une telle date et de la récupérer.
public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) throws SecurityException
Le ContentHandlerFactory instancie le gestionnaire de contenu approprié à un type MIME donné. Cette méthode permet de préciser le ContentHandlerFactory que doit utiliser le programme courant. Elle ne peut être appelée qu’une seule fois par exécution sans quoi elle retourne une erreur.
public String toString ()
Méthode de la classe Object surchargée pour renvoyer une chaîne de caractères décrivant la connexion. Cette méthode est rarement utilisé en dehors du débogage.