Un réseau informatique est constitué d'un ensemble d'ordinateurs et de périphériques interconnectés. Un noeud du réseau qui correspond à un ordinateur est généralement appelé hôte .
TCP/IP est l'architecture réseau la plus répandue. Contrairement à ce que son nom laisse croire, TCP/IP n'est pas une architecture réduite à deux protocoles : IP (Internet Protocol) et TCP (Transmission Control Protocol). L'architecture TCP/IP inclut de nombreux "services d'application", des protocoles élaborés et complexes, sur lesquels les applications distribuées peuvent s'appuyer. Sans rentrer dans les détails, le schéma suivant précise les divers couches du réseau où interviennent les protocoles IP, TCP, et UDP.

Les couches réseau
Les couches les plus basses, Ligne, Physique, et Réseau ne sont pas incluses dans l'architecture TCP/IP. En fait, TCP/IP s'appuie sur n'importe quelles couches basses existantes :
Le protocole IP comporte des limitations notables :
Les applications désirant communiquer via IP disposent de deux alternatives :
Il existe des applications toutes les données sont vitales et aucune perte de données n'est tolérable; dans ces cas, on choisira d'utiliser le protocole TCP. Par contre, il existe d'autres applications ou un perte de quelques données est sans conséquence: dans ces, on utilisera plutôt le protocole UDP.
Parallèlment aux adresses, les noeuds possèdent un nom plus parlant pour l'être humain. Le serveur du département GBM de l'ESIL ne nomme gbm.esil.univ-mrs.fr. Ce nom est totalement indépendant de l'adresse internet ce qui permet de changer l'adresse internet d'une machine sans devoir forcément changer son nom.
Les données qui circulent dans un réseau sont découpés en tronçons d'une certaine taille; ces tronçon sont appelés paquets .
Les ordinateurs communiquent entre eux à travers un protocole: il s'agit d'une convention que reconnaît les machines émettrices et les machines réceptrices. Un exemple typique d'une protocole est le protocole HTTP qui définit les modalités de communication entre un navigateur WEB et un serveur de pages HTML. Il existe bien d'autres protocoles: file, ftp, gopher, news, telnet, WAIS, etc.

Dialogue Client/Serveur
Chaque machine sous IP possède quelques 65 535 ports; par exemple, le service HTTP est lié au port 80, le service SMTP (courrier électronique) est relié au port 25, etc.
Une machine cliente qui s'adresse à une machine serveur le fait en spécifiant son adresse internet et le numéro de port qui l'intéresse.
Une différence importante au niveau de l'utilisation des ports TCP et UDP est la suivante
Avec TCP, il sera aisé de concevoir des applications serveur "multi-processus" : chaque processus sera en charge de gérer une relation client-serveur, via une connexion TCP; chaque processus possède une file d'attente propre. Avec UDP, c'est impossible : la même file d'attente sera utilisée par tous les processus.
Avec UDP, les seules applications serveur qui pourront fonctionner en version "multi-processus" seront celles conçues pour accepter une requête et renvoyer immédiatement une réponse, et une seule. C'est le cas de nombreuses applications dites " transactionnelles" : les requêtes sont sérialisées par le port UDP; chacune est traitée par un processus, la réponse est ensuite envoyée. Les requêtes consécutives ne doivent pas être corrélées.
Avec TCP et UDP, un certain nombre de ports sont réservés à des services bien connus. Par exemple, sur TCP :
Sur UDP :
Ces ports alloués statiquement, aussi appelés Well Known Ports , correspondant à des Well Known Services (WKS) , dans un espace de port réservé au serveur :
Sous Unix, les ports réservés pour les "services bien connus" sont visibles dans le fichier /etc/services. Par exemple :
tcpmux 1/tcp # TCP port multiplexer (RFC 1078) echo 7/tcp echo 7/udp ftp-data 20/tcp ftp 21/tcp telnet 23/tcp smtp 25/tcp mail domain 53/tcp nameserver # name-domain server domain 53/udp nameserver bootp 67/udp bootps # bootp server bootpc 68/udp # bootp client tftp 69/udp finger 79/tcp iso-tsap 102/tcp snmp 161/udp snmp-trap 162/udp snmptrap xdmcp 177/udp # X Display Mgr. Control Prot. route 520/udp router routed
<protocole>://<nom_hote>[:<port>]/<chemin>/<nom_fichier>#<section>
Tout comme pour les fichiers dans un système de fichiers, une ressource internet peut être spécifié soit par son URL absolu soit par son URL relatif. Un URL relatif désigne une ressource qui peut être désigné relativement au document courant. Les URL relatifs ne peuvent référencer que des ressources qui se trouvent dans le même hôte que le document où figure l'URL.
Le protocole de communication HHTP consiste :
A TERMINER
A TERMINER
Les CGI (Commun Gateway Interface ) sont des programmes qui résident et s'exécutent sur le serveur. ces programmes sont déclenchés en réponse à la demande d'un client à travers une page HTML. C'est une manière de réaliser des pages WEB dynamiques.
Comme ce sont des programmes qui résident sur le serveur et qui s'exécutent sur le serveur, il n'y a aucune restriction quant au choix du langage utilisé. Dans la pratique, on constante que les CGI sont, le plus souvent, des programmes réalisés en C, Perl ou AppleScript; même s'il est tout à fait possible de réaliser des CGI en Java, C++, Pascal, Prolog, Lisp, et tout autre langage de programmation.
la classe java.net contient les classes
et les interfaces
Comme nous l'avons dit, un hôte sur le réseau peut être nommé soit par son adresse internet soit son nom DNS; leur manipulation se fait par la classe java.net.InetAddress.
public final class InetAddress extends Object implements Serializable { public boolean isMulticastAddress() public String getHostName() public byte[] getAddress() public String getHostAddress() public int hashCode() public boolean equals(Object obj) public String toString() public static InetAddress getByName(String host) throws UnknownHostException public static InetAddress[] getAllByName(String host) throws UnknownHostException public static InetAddress getLocalHost() throws UnknownHostException }
Cette classe ne possède pas de constructeur. En général, les instances de InetAddress s'obtiennent comme résultat des méthodes static: getByName, getAllByName et getLocalHost.
public static InetAddress getByName (String host) throws UnknownHostException
Retourne un objet de la classe InetAddress codant l'adresse IP d'un hôte. L'argument host est le nom DNS de l'hôte ou son adresse IP.
public static InetAddress[] getAllByName (String host) throws UnknownHostException
Retourne un tableau d'objets de la classe InetAddress codant toutes les adresses IP d'un hôte. L'argument host est le nom DNS de l'hôte ou son adresse IP.
public static InetAddress getLocalHost () throws UnknownHostException
Retourne un objet de la classe InetAddress codant l'adresse IP du hôte local.
Retourne une chaîne de caractères contenant le nom d'hôte de l'objet InetAddress ou son adresse IP (si le nom n'existe pas).public byte[] getAddress ()
Retourne un tableau d'octet contenant les 4 octets de l'adresse IP de l'objet InetAddress.public String getHostAddress ()
Retourne une chaîne de caractères contenant les 4 octets de l'adresse IP de l'objet InetAddress; cette chaîne est de la forme "%d.%d.%d.%d".
import java.net.*; public class Adresses { public static void main(String[] args) { for(int i=0 ; i< args.length; i++) { try { InetAddress[] inetadrs = InetAddress.getAllByName(args[i]); System.out.println(args[i] + ":"); for(int j=0 ; j<inetadrs.length ; j++) System.out.println(inetadrs[j]); } catch (UnknownHostException e) { System.out.println(args[i] + " inconnu !!! "); } } } }
Applet
Comme nous l'avons déjà dit, une URL désigne une ressource dans une réseau sous le format suivant:
protocole://nom_hote[:port]/chemin/nom_fichier#section
En Java , l'URL n'est pas représenté par une chaîne de caractères mais par une instance de la classe java.net.URL
public final class URL extends Object implements Serializable, Comparable { public URL(String protocol, String host, int port, String file) throws MalformedURLException public URL(String protocol, String host, String file) throws MalformedURLException public URL(String spec) throws MalformedURLException public URL(URL context, String spec) throws MalformedURLException protected void set(String protocol, String host, int port, String file, String ref) public int getPort() public String getProtocol() public String getHost() public String getFile() public String getRef() public boolean equals(Object obj) public int hashCode() public int compareTo(Object url) public boolean sameFile(URL other) public String toString() public String toExternalForm() public URLConnection openConnection() throws IOException public final InputStream openStream() throws IOException public final Object getContent() throws IOException public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) }
La classe URL dispose de quatre constructeurs:
Crée une instance de URL à partir du protocole prot, de l'hôte h, du port p et du fichier f.
URL url = new URL("http", "gbm.esil.univ-mrs.fr", 80, "eleves/index.html");
Crée une instance de URL à partir du protocole prot, de l'hôte h et du fichier f. Le port choisi est le port par défaut du protocole spécifié.
URL url = new URL("http", "gbm.esil.univ-mrs.fr", "eleves/index.html");
Crée une instance de URL à partir de sa représentation textuelle.
URL url = new URL("http://gbm.esil.univ-mrs.fr/eleves/index.html");
URL gbm = new URL("http://gbm.esil.univ-mrs.fr"); URL eleves = new URL(gbm, "eleves/index.html");
Tous ces constructeurs lève l'exception MalformedURLException lorsque le protocole spécifié est inconnu. Vous aurez noté qu'une instance de URL est une sorte de constante puisque la classe URL ne fournit aucune méthode pour modifier le protocole ou l'hôte, etc.
Par contre, il est possible de consulter les attributs d'une URL. Les méthodes getPort, getProtocol, getHost, getFile et getRef permettent de récupérer le port, le protocole, l'hôte, le fichier et la section du fichier.
Pour illustrer tout ceci, voici un exemple provenant du tutorial de JDK:
et voici le résultat de l'exécution de ce programme:
import java.net.*; import java.io.*; public class ParseURL { public static void main(String[] args) throws Exception { URL aURL = new URL("http://java.sun.com:80/docs/books/tutorial/intro.html#DOWNLOADING"); System.out.println("protocol = " + aURL.getProtocol()); System.out.println("host = " + aURL.getHost()); System.out.println("filename = " + aURL.getFile()); System.out.println("port = " + aURL.getPort()); System.out.println("ref = " + aURL.getRef()); } }
protocol = http host = java.sun.com filename = /docs/books/tutorial/intro.html port = 80 ref = DOWNLOADING
Pour récupérer des données à partir d'une URL, la classe URL fournit les méthodes openConnection, openStream et getContent:
public URLConnection openConnection () throws IOException
Retourne une instance de la classe URLConection qui représente une connexion vers vers l'objet désigné par l'url. Ceci peut sembler un peu mystérieux pour le moment; tout ceci devrai s'éclaircir un peu plus loin.public final Object getContent () throws IOException
Retourne le contenu de l'url. C'est un raccourci pour openConnection().getContent()public final InputStream openStream () throws IOException
Cette méthode établit la communication entre le client et le serveur en ouvrant un InputStream . Equivalent à openConnection().openStream().
import java.io.*; import java.net.*; public class OpenURL { public static void main(String[] args) { BufferedReader in = null; try { if (args.length != 1) { System.out.println("usage: java OpenURL <URL>"); System.exit(0); } URL url = new URL(args[0]); in = new BufferedReader(new InputStreamReader(url.openStream())); String s; while ( (s=in.readLine()) != null) System.out.println(s); } catch (IOException e) {System.out.println("Erreur1");} catch (Exception e) {System.out.println("Erreur2");} finally { try { if (in != null) in.close(); } catch (Exception e) {System.out.println("Erreur3");} } } }et voici une partie de l'affichage produit:
Java OpenURL http://gbm.esil.univ-mrs.fr/~tourai/index.htmlTouraïvane ... ...
public boolean sameFile (URL other)
public String toString ()
A TERMINER
public String toExternalForm ()
A TERMINER
public static void setURLStreamHandlerFactory (URLStreamHandlerFactory fac)
A TERMINER
A TERMINER
TCP/IP offre, en particulier, une interface dite sockets pour l'écriture d'applications communicantes. Les sockets a été introduit avec le système d'exploitation UNIX de Berkeley. L'idée des sockets est de faire en sorte que deux programmes sur des hôtes différents puissent communiquer l'un avec l'autre à travers sans se soucier des détails de bas niveau de la communication réseau.
Les primitives TCP pour les sockets permettent :
Les sockets ne sont pas des objets spécifiquement réseaux, et encore moins spécifiquement TCP/IP. Ce sont des objets génériques qui doivent être paramétrés lors de leur création selon l'utilisation prévue :
Dans la communication par sockets, il existe toujours une machine qui joue le rôle du serveur et l'autre (ou les autres) qui joue le rôle de client.
Le serveur est une application qui tourne sur un hôte et qui est à l'écoute des requêtes d'un ou de plusieurs clients sur un port particulier.
Le client est une application qui tourne un hôte (pas forcément différent de celui sur lequel tourne le serveur). Il doit connaître l'hôte et le port sur lequel le serveur est à l'écoute; le client tente alors une connexion au serveur sur l'hôte et le port approprié.
Lorsque le serveur est conçu pour communiquer avec plusieurs clients, quand tout se passe bien,
Les programmes serveurs doivent toujours être actifs lorsque des clients initient une connexion. Il existe deux façons d'assurer que ces serveurs soient activés :
Une telle ligne signifie que service est implanté sur cette machine, que les sockets utilisés sont de type stream, que le protocole utilisé est tcp, que le programme à activer lors d'une demande de service est /usr/etc/progd, que le nom à donner au programme sera progd, que le programme doit s'exécuter avec comme propriétaire root.
service stream tcp nowait root /usr/etc/progd progd
Le paramètre nowait indique que plusieurs instances de ce programme peuvent être activées sans attendre la terminaison des instances précédantes.
Cette ligne indique que pour le service défini dans le fichier inetd.conf, il faut utiliser le port 78 du protocole tcp. Le reste de la ligne est un alias possible pour le nom du service. Une fois ces informations récupérées, le serveur inetd va créer un socket, lui associer le numéro de port, et se mettre en attente d'une indication d'établissement de connexion à ce port. Comme de nombreux services existent, le superserveur inetd crée de nombreux sockets, assigne les numéros de port adéquats, se met en attente, etc..
service 78/tcp alias_service
Le paramètre dgram identifie un socket de type datagramme, udp indique que le protocole utilisé est UDP, wait indique qu'il faut attendre la terminaison d'une instance du service avant de pouvoir en lancer la suivante. Notons que si les programmes serveurs sont conçus pour s'exécuter en parallèle (voir chapitre 5), on peut trouver la ligne suivante dans le fichier /etc/inetd.conf :
service dgram udp wait root /usr/etc/progd progd
Dans les deux cas, on devra trouver la ligne correspondante dans le fichier /etc/services :
service dgram udp nowait root /usr/etc/progd progd
service 78/udp alias_service
Java fournit deux classes pour la gestion des sockets:
public class Socket { protected Socket() protected Socket(SocketImpl impl) throws SocketException 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 public Socket(String host, int port, boolean stream) throws IOException public Socket(InetAddress host, int port, boolean stream) throws IOException public InetAddress getInetAddress() public InetAddress getLocalAddress() public int getPort() public int getLocalPort() public InputStream getInputStream() throws IOException public OutputStream getOutputStream() throws IOException public void setTcpNoDelay(boolean on) throws SocketException public boolean getTcpNoDelay() throws SocketException public void setSoLinger(boolean on, int val) throws SocketException public int getSoLinger() throws SocketException public void setSoTimeout(int timeout) throws SocketException public int getSoTimeout() throws SocketException public void close() throws IOException public String toString() public static void setSocketImplFactory(SocketImplFactory fac) throws IOException }
Une application cliente doit ouvrir une connexion sur en créant un socket.
La connexion établie, les canaux d'entrée/sortie s'obtiennent grâce aux méthode getInputStream et getOutputStream.
try { socket sock = new Socket("gbm.esil.univ-mrs.fr", 2000); } catch (UnknoxnHostException e) { System.out.println("Hôte inconnu"); System.exit(-1); } catch (IOException e) { System.out.println("Erreur lors de connexion"); System.exit(-1);}
Pour tester le client, mous allons utiliser une application serveur qui existe sur tous les systèmes UNIX et qui est à l'écoute du port 7: il s'agit du serveur echo qui se contente de renvoyer au client la chaîne que ce dernier lui envoie.
import java.io.*; import java.net.*; public class Client { public static void main(String[] args) throws Exception, NumberFormatException { Socket serveur = new Socket("gbm.esil.univ-mrs.fr", Integer.parseInt(args[0])); PrintWriter Sout = new PrintWriter(serveur.getOutputStream()); BufferedReader Sin = new BufferedReader(new InputStreamReader(serveur.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String jEnvoie, jeReçois; do { jEnvoie = in.readLine(); Sout.println(jEnvoie); Sout.flush(); jeReçois = Sin.readLine(); System.out.println(jeReçois); } while (! jEnvoie.equals("fin")); Sin.close(); Sout.close(); serveur.close(); } }
public class ServerSocket { public ServerSocket(int port) throws IOException public ServerSocket(int port, int backlog) throws IOException public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException public InetAddress getInetAddress() public int getLocalPort() public Socket accept() throws IOException protected final void implAccept(Socket s) throws IOException public void close() throws IOException public void setSoTimeout(int timeout) throws SocketException public int getSoTimeout() throws IOException public String toString() public static void setSocketFactory(SocketImplFactory fac) throws IOException }
Une application serveur doit créer un instance ServerSocket:
Une fois le serveur crée, il va se mettre en attente d'une connexion cliente:
try { ServerSocket sock = new ServerSocket(2000); } catch (IOException e) { System.out.println("Erreur de création du serveur sur le port 2000"); System.exit(-1); }
Socket sockClient; try { sockClient= serverSocket.accept(); } catch (IOException e) { System.out.println("Echec de la mise en attente sur le port 2000"); System.exit(-1); }
La méthode accept permet au serveur d'être à l'écoute du port 2000 et d'attendre une future connexion cliente. Lorsqu'une telle connexion s'établit, la varibale sockClient permet de récupérer le canal de communication établit avec le client grâce aux méthodes getInputStream et getOutputStream.
Pour illustrer le fonctionnement du serveur, programmons le fameux serveur echo.
import java.io.*; import java.net.*; public class TestEcho { public static void main(String[] args) throws Exception { ServerSocket serveur = new ServerSocket(2000); while (true) { Socket client = serveur.accept(); PrintWriter Cout = new PrintWriter(client.getOutputStream()); BufferedReader Cin = new BufferedReader(new InputStreamReader(client.getInputStream())); String jeReçois; do { jeReçois = Cin.readLine(); Cout.println("Vous avez dit " + jeReçois); Cout.flush(); } while (! jeReçois.equals("fin")); Cin.close(); Cout.close(); client.close(); } } }
Le serveur TestEcho est bien trop simpliciste. En effet, ce serveur n'accepte qu'un client à la fois. Que se passe-t-il si plusieurs clients essayent de se connecter en même temps ? Le premier qui se connecte monopolise la connexion et les autres clients doivent attendre la fin de communication du premier pour pouvoir dialoguer avec le serveur à tour de rôle.
Cette solution est très restrictive. Nous allons modifier le serveur pour qu'il puisse répondre à plusieurs clients à la fois. Pour ce faire, le serveur devra créer un thread par client connecté de manière à pouvoir se remettre en attente d'un éventuel futur client.
Le squelette d'un programme qui réalise ceci est de la forme:
while (true) { attente d'un connexion créer un thread pour dialoguer avec le client qui s'est connecté }
import java.io.*; import java.net.*; public class TestEchoMultiple { public static void main(String[] args) throws Exception { ServerSocket serveur = new ServerSocket(2000); while (true) { Socket client = serveur.accept(); System.out.println("C'est par"); new EncoreUnClient(client).start(); } } } class EncoreUnClient extends Thread { Socket client; public EncoreUnClient(Socket client) { super("Clients"); this.client = client; } public void run() { PrintWriter Cout = null; BufferedReader Cin = null; try { System.out.println("C'est parti"); Cout = new PrintWriter(client.getOutputStream()); Cin = new BufferedReader(new InputStreamReader(client.getInputStream())); String jeReçois; do { jeReçois = Cin.readLine(); Cout.println("Vous avez dit " + jeReçois); Cout.flush(); } while (! jeReçois.equals("fin")); if (Cin != null) Cin.close(); if (Cout != null) Cout.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } }
On dispose de deux classes pour la communication par UDP:
Ainsi, l'envoi de données par UDP consite à les confier à un DatagramPacket en vue de leur emballage sous forme de paquets et à envoyer ce DatagramPacket à un DatagramSocket pour leur expédition. Un DatagramSocket se charge de la récéption; les paquets reçus doivent être mis dans un DatagramPacket en vue de leur déballage.
public final class DatagramPacket { public DatagramPacket(byte ibuf[], int ilength) public DatagramPacket(byte ibuf[], int ilength, InetAddress iaddr, int iport) public synchronized InetAddress getAddress() public synchronized int getPort() public synchronized byte[] getData() public synchronized int getLength() public synchronized void setAddress(InetAddress iaddr) public synchronized void setPort(int iport) public synchronized void setData(byte ibuf[]) public synchronized void setLength(int ilength) }
La classe DatagramPacket dispose de deux constructeurs
où
public DatagramPacket(byte ibuf[], int ilength) public DatagramPacket(byte ibuf[], int ilength, InetAddress iaddr, int iport)
Les méthodes getAddress, getPort, getLength et getData permettent de récupérer respectivement l'adresse de destination, le port de destination, la taille du paquet et les données contenues dans le paquet.
Les méthodes setAddress, setPort, setLength et setData assigne respectivement l'adresse de destination, le port de destination, la taille du paquet et les données contenues dans le paquet.
Class java.net.DatagramSocket { public DatagramSocket() throws SocketException public DatagramSocket(int port) throws SocketException public DatagramSocket(int port, InetAddress laddr) throws SocketException public void send(DatagramPacket p) throws IOException public synchronized void receive(DatagramPacket p) throws IOException public InetAddress getLocalAddress() public int getLocalPort() public synchronized void setSoTimeout(int timeout) throws SocketException public synchronized int getSoTimeout() throws SocketException public void close() }
La classe DatagramSocket possède trois constructeurs:
Crée un socket datagramme et l'associe à un port quelconque de la machine locale.
public DatagramSocket() throws SocketException
Crée un socket datagramme et l'associe à un port numport de la machine locale.
public DatagramSocket(int numport) throws SocketException
Crée un socket datagramme et l'associe à un port numport de la machine d'adresse laddr.
public DatagramSocket(int numport, InetAddress laddr) throws SocketException
Les méthodes send et receive de cette classe permettent d'envoyer et de recevoir les packets UDP.
La méthode send lève une exception lorsque le SecurityManager refuse l'envoi d'un paquet vers l'hôte spécifié. C'est le cas ou une erreur peut se produire.
La méthode receive (tout comme la méthode accept de la classe SocketServer) se met en attente et lève également une exception lorsqu'il y une erreur dans la reception du paquet UDP. La méthode receive doit disposer d'un tampon assez grand pour le packet à recevoir. Dans le cas contraire, le paquet est tronqué à la taille du tampon.
La connexion établie, les canaux d'entrée/sortie s'obtiennent grâce aux méthode getInputStream et getOutputStream.
try { socket sock = new Socket("gbm.esil.univ-mrs.fr", 2000); } catch (UnknoxnHostException e) { System.out.println("Hôte inconnu"); System.exit(-1); } catch (IOException e) { System.out.println("Erreur lors de connexion"); System.exit(-1);}
Pour tester le client, mous allons utiliser une application serveur qui existe sur tous les systèmes UNIX et qui est à l'écoute du port 7: il s'agit du serveur echo qui se contente de renvoyer au client la chaîne que ce dernier lui envoie.
import java.io.*; import java.net.*; public class Client { public static void main(String[] args) throws Exception, NumberFormatException { Socket serveur = new Socket("gbm.esil.univ-mrs.fr", Integer.parseInt(args[0])); PrintWriter Sout = new PrintWriter(serveur.getOutputStream()); BufferedReader Sin = new BufferedReader(new InputStreamReader(serveur.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String jEnvoie, jeReçois; do { jEnvoie = in.readLine(); Sout.println(jEnvoie); Sout.flush(); jeReçois = Sin.readLine(); System.out.println(jeReçois); } while (! jEnvoie.equals("fin")); Sin.close(); Sout.close(); serveur.close(); } }
Et voici à présent un serveur UDP à l'image du serveur TCP que nous vu. Il faut donc :
DatagramSocket socket = new DatagramSocket(2001);
DatagramPacket paquet = new DatagramPacket(buf, buf.length);
socket.receive(paquet);
InetAddress address = paquet.getAddress(); int port = paquet.getPort(); jeReçois = new String(paquet.getData(), 0, paquet.getLength());
paquet = new DatagramPacket(buf, buf.length, address, port); socket.send(paquet);
Et voici le programme complet.
import java.io.*; import java.net.*; public class UdpTestEcho { public static void main(String[] args) throws Exception { String jeReçois; DatagramSocket socket = new DatagramSocket(2001); while (true) { byte[] buf = new byte[56]; DatagramPacket paquet = new DatagramPacket(buf, buf.length); socket.receive(paquet); jeReçois = new String(paquet.getData(), 0, paquet.getLength()); System.out.println("j'ai recu : " + jeReçois + " " + jeReçois.length()); InetAddress address = paquet.getAddress(); int port = paquet.getPort(); paquet = new DatagramPacket(buf, buf.length, address, port); socket.send(paquet); } } }
On entend par gestion de protocole la prise en charge du protocole, le traitement des données spécifiques et leur présentation à l'utilisateur. La classe URLConnection sert également à cette gestion; ce que nous verrons dans la section suivante.
public abstract class URLConnection { protected URL url protected boolean doInput protected boolean doOutput protected boolean allowUserInteraction protected boolean useCaches protected long ifModifiedSince protected boolean connected protected URLConnection(URL url) public static FileNameMap getFileNameMap() public static void setFileNameMap(FileNameMap map) public abstract void connect() throws IOException public URL getURL() public int getContentLength() public String getContentType() public String getContentEncoding() public long getExpiration() public long getDate() public long getLastModified() 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) public Object getContent() throws IOException public InputStream getInputStream() throws IOException public OutputStream getOutputStream() throws IOException public String toString() public void setDoInput(boolean doinput) public boolean getDoInput() public void setDoOutput(boolean dooutput) public boolean getDoOutput() public void setAllowUserInteraction(boolean allowuserinteraction) public boolean getAllowUserInteraction() public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) public static boolean getDefaultAllowUserInteraction() public void setUseCaches(boolean usecaches) public boolean getUseCaches() public void setIfModifiedSince(long ifmodifiedsince) public long getIfModifiedSince() public boolean getDefaultUseCaches() public void setDefaultUseCaches(boolean defaultusecaches) public void setRequestProperty(String key, String value) public String getRequestProperty(String key) public static void setDefaultRequestProperty(String key, String value) public static String getDefaultRequestProperty(String key) public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) protected static String guessContentTypeFromName(String fname) public static String guessContentTypeFromStream(InputStream is) throws IOException }
On obtient généralement une instance de la classe URLConection en retour de l'invocation de la méthode openConnection de la classe URL.
La seule méthode abstraite de cette classe est la méthode connect; toutes les autres méthodes sont implantées.
... URL u = new URL("http://gbm.esil.univ-mrs.fr/index.html"); URLConnection uc = u.openConnection(); ...
Les méthodes principales de cette classe sont connect, getContent, getInputStream et getOutputStream.
La méthode abstraite connect permet d'ouvrir une connection vers un url. Cette méthode est redéfinie par les sous classes de la classe URLConnection; c'est le cas de la classe HttpURLConnection. La méthode connect est rarement utilisé, c'est la méthode openConnection qui invoque cette méthode pour la bonne version de protocole.
La méthode getContent est celle invoquée par la méthode de même nom de la classe URL: elle retoune le contenu d'une url. L'exception UnknownServiceException est levée si le protocole et/ou le type MIME de l'url n'est pas reconnu.
La méthode getInputStream peut être utilisé lorsque getContent ne peut l'être. L'utilisation de cette méthode est similaire à la méthode openStream de la classe URL.
... URL = u = new URL(...); URLConnection uc = u.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader(url.openInputStream())); ... String s = in.readLine(); ...
La méthode getOutputStream permet d'envoyer des données à une url (méthode POST des CGI par exemple). Avant d'utiliser cette méthode, il faut invoquer la méthode setDoOutput car, par défaut, les URLConnection ne permettent pas d'envoyer des données.
... URL = u = new URL("http://gbm.esil.univ-mrs/cgi_bin/programme); URLConnection uc = u.openConnection(); uc.setDoOutput(true); PrintWriter out = new PrintWriter(url.openOutputStream()); out.writeln(...); ...
Les méthodes getContentType, getContentLength,getContentEncoding permettent de consulter le type MIME, la longueur et le type d'encodage.
Les méthodes getHeaderField, getHeaderFieldKey, getHeaderFieldKeyDate et getHeaderFieldKeyInt permettent de récupérer les informations insérées dans les entêtes MIME.
import java.io.*; import java.net.*; import java.util.*; public class TestContent { public static void main(String[] args) { BufferedReader in = null; try { if (args.length != 1) { System.out.println("usage: java OpenURL <URL>"); System.exit(0); } URL url = new URL(args[0]); URLConnection uc = url.openConnection(); System.out.println(uc.getContentType()); System.out.println(uc.getContentLength()); System.out.println(uc.getContentEncoding()); System.out.println(new Date(uc.getDate())); System.out.println(new Date(uc.getExpiration())); System.out.println(new Date(uc.getLastModified())); int i=0; String nom=null; do { System.out.println(uc.getHeaderFieldKey(i) + ": " + (nom=uc.getHeaderField(i++))); } while (nom != null); System.out.println(uc.getHeaderField("content-type")); System.out.println(uc.getHeaderField("content-length")); System.out.println(uc.getHeaderField("date")); } catch (IOException e) { System.out.println("Erreur1");} catch (Exception e) { System.out.println("Erreur2");} finally { try { if (in != null) in.close(); } catch (Exception e) { System.out.println("Erreur3");} } } }
A priori, si toutes les conventions de nommage sont respectées, le type MIME peut se déduire aisément de l'extension du nom du la ressource url spécifié.
| Extension | Type MIME .pdf |
En exécutant l'exemple précédant, on obtient bien le type des fihciers spécifiés:
Par contre si l'extension n'est pas correct, on alors des surprises; le fichier photo est une copie renommée du fichier photo.jpg
% java TestContent http://gbm.esil.univ-mrs.fr/~tourai/images/photo.jpg Content-type: text/html
% java TestContent http://gbm.esil.univ-mrs.fr/~tourai/images/photo Content-type: text/plain
Aussi, Java dispose de deux méthodes pour deviner le type MIME associé à un fichier:
qui tente d'associer un type MIME en fonction de l'extension du nom
protectd Static String guessContentTypeFromName(String)
qui tente d'associer un type MIME en analysant les premier octets.
protectd Static String guessContentTypeFromStream(InputStream is)
A TERMINER
A TERMINER
A TERMINER
A TERMINER
A TERMINER