Blue Flower

Chercher

La communication par socket en Java

L'interface socket BSD, l'interface de programmation réseau la plus courante, permet la communication par socket selon le schéma habituel client-serveur. Dans java l'interface des sockets qui se trouve dans le package "java.net" permet un accès simple aux sockets sur IP.

Les classes

Pour réaliser une communication par socket en java on se sert, de la classe "java.net.InetAddress" pour manipuler des adresses IP, de la classe "java.net.SocketServer" côté serveur si on travaille en mode connecté. La classe "java.net.Socket" permet de programmer l'interface côté client et la communication effective par flot via les sockets. Les classes java.net.DatagramSocket et java.net.DatagramPacket servent à programmer la communication en mode datagramme.

1. La classe java.net.InetAddress

Cette classe représente les adresses IP et un ensemble de méthodes pour les manipuler. Elle encapsule aussi l'accès au serveur de noms DNS et elle a comme signature:

   public class InetAddress implements Serializable

1.1 Les opérations de la classe InetAddress

Conversion de nom vers adresse IP :

Un premier ensemble de méthodes permet de créer des objets adresses IP.

   public static InetAddress getLocalHost() throws UnknownHostException

Cette méthode renvoie l'adresse IP du site local d'appel.

    public static InetAddress getByName(String host) throws UnknownHostException

Cette méthode construit un nouvel objet InetAddress à partir d'un nom textuel de site. Le nom du site est donné sous forme symbolique (ocamil.com) ou sous forme numérique (147.120.17.03).

Enfin,

   public static InetAddress[] getAllByName(String host) throws UnknownHostException

permet d'obtenir les différentes adresses IP d'un site.

Conversions inverses

Des méthodes applicables à un objet de la classe InetAddress permettent d'obtenir dans divers formats des adresses IP ou des noms de site. Les principales sont :

public String getHostName() obtient le nom complet correspondant à l'adresse IP
public String getHostAddress() obtient l'adresse IP sous forme %d.%d.%d.%d
public byte[] getAddress() obtient l'adresse IP sous forme d'un tableau d'octets.

1.2 La classe ServerSocket

Cette classe implante un objet ayant un comportement de serveur via une interface par socket.

   public class java.net.ServerSocket

Une implantation standard du service existe mais peut être redéfinie en donnant une implantation explicite sous la forme d'un objet de la classe java.net.SocketImpl. Nous nous contenterons d'utiliser la version standard.

1.2.1 Le constructeur 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

Ces constructeurs créent un objet serveur à l'écoute du port spécifié. La taille de la file d'attente des demandes de connexion peut être explicitement spécifiée via le paramètre backlog. Si la machine possède plusieurs adresses, on peut aussi restreindre l'adresse sur laquelle on accepte les connexions.

Appels système :

ce constructeur correspond à l'utilisation des primitives socket, bind et listen.

1.2.2 Les opérations de la classe ServerSocket

Nous ne retiendrons que les méthodes de base. La méthode essentielle est l'acceptation d'une connexion d'un client :

    public Socket accept() throws IOException

Cette méthode est bloquante, mais l'attente peut être limitée dans le temps par l'appel préalable de la méthode setSoTimeout. Cette méthode prend en paramètre le délai de garde exprimé en millisecondes. La valeur par défaut 0 équivaut à l'infini. À l'expiration du délai de garde, l'exception java.io.InterruptedIOException est levée.

    public void setSoTimeout(int timeout) throws SocketException

La fermeture du socket d'écoute s'exécute par l'appel de la méthode close.

Enfin, les méthodes suivantes retrouvent l'adresse IP ou le port d'un socket d'écoute :

   public InetAddress getInetAddress() 
    public int getLocalPort()

1.3 La classe java.net.Socket

La classe java.net.Socket est utilisée pour la programmation des sockets connectés, côté client et côté serveur.

   public class java.net.Socket

Comme pour le serveur, nous utiliserons l'implantation standard bien qu'elle soit redéfinissable par le développement d'une nouvelle implantation de la classe java.net.SocketImpl.

1.3.1 Constructeurs

Côté serveur, la méthode accept de la classe java.net.ServerSocket renvoie un socket de service connecté au client. Côté client, on utilise :

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 UnknownHostException, IOException
    public Socket(InetAddress addr, int port, InetAddress localAddr, int localPort)
                throws IOException

Les deux premiers constructeurs construisent un socket connecté à la machine et au port spécifiés. Par défaut, la connexion est de type TCP fiable. Les deux autres interfaces permettent en outre de fixer l'adresse IP et le numéro de port utilisés côté client (plutôt que d'utiliser un port disponible quelconque).

Appels système :

ces constructeurs correspondent à l'utilisation des primitives socket, bind (éventuellement) et connect.

1.3.2 Opérations de la classe Socket

La communication effective sur une connexion par socket utilise la notion de flots de données (java.io.OutputStream et java.io.InputStream). Les deux méthodes suivantes sont utilisés pour obtenir les flots en entrée et en sortie.

 public InputStream  getInputStream()  throws IOException
    public OutputStream getOutputStream() throws IOException

Les flots obtenus servent de base à la construction d'objets de classes plus abstraites telles que java.io.DataOutputStream et java.io.DataInputStream (pour le JDK1), ou java.io.PrintWriter et java.io.BufferedReader (JDK2 et +).

Une opération de lecture sur ces flots est bloquante tant que des données ne sont pas disponibles. Cependant, il est possible de fixer un délai de garde à l'attente de données (similaire au délai de garde du socket d'écoute : levée de l'exception java.io.InterruptedIOException) :

 public void setSoTimeout(int timeout) throws SocketException

Un ensemble de méthodes permet d'obtenir les éléments constitutifs de la liaison établie :

public InetAddress getInetAddress() fournit l'adresse IP distante
public InetAddress getLocalAddress() fournit l'adresse IP locale
public int getPort() fournit le port distant
public int getLocalPort() fournit le port local


L'opération close ferme la connexion et libère les ressources du système associées au socket.

1.4 Socket en mode datagramme DatagramSocket

La classe java.net.DatagramSocket permet d'envoyer et de recevoir des paquets (datagrammes UDP). Il s'agit donc de messages non fiables (possibilités de pertes et de duplication), non ordonnés (les messages peuvent être reçus dans un ordre différent de celui d'émission) et dont la taille (assez faible -- souvent 4Ko) dépend du réseau sous-jacent.

 public class java.net.DatagramSocket

1.4.1 Constructeurs

public DatagramSocket() throws SocketException
    public DatagramSocket(int port) throws SocketException

Construit un socket datagramme en spécifiant éventuellement un port sur la machine locale (par défaut, un port disponible quelconque est choisi).

1.4.2 Émission/réception

public void send(DatagramPacket p) throws IOException
public void receive(DatagramPacket p) throws IOException

Ces opérations permettent d'envoyer et de recevoir un paquet. Un paquet est un objet de la classe java.net.DatagramPacket qui possède une zone de données et (éventuellement) une adresse IP et un numéro de port (destinataire dans le cas send, émetteur dans le cas receive). Les principales méthodes sont :

 public DatagramPacket(byte[] buf, int length)
    public DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    public InetAddress getAddress()
    public int getPort()
    public byte[] getData()
    public int getLength()
    public void setAddress(InetAddress iaddr)
    public void setPort(int iport)
    public void setData(byte[] buf)
    public void setLength(int length)

Les constructeurs renvoient un objet pour recevoir ou émettre des paquets. Les accesseurs get* permettent, dans le cas d'un receive, d'obtenir l'émetteur et le contenu du message. Les méthodes de modification set* permettent de changer les paramètres ou le contenu d'un message pour l'émission.

1.4.3 Connexion

Il est possible de « connecter » un socket datagramme à un destinataire. Dans ce cas, les paquets émis sur le socket seront toujours pour l'adresse spécifiée. La connexion simplifie l'envoi d'une série de paquets (il n'est plus nécessaire de spécifier l'adresse de destination pour chacun d'entre eux) et accélère les contrôles de sécurité (ils ont lieu une fois pour toute à la connexion). La « déconnexion » enlève l'association (le socket redevient disponible comme dans l'état initial).

 public void connect(InetAddress address, int port)
    public void disconnect()

1.4.4 Divers

Diverses méthodes renvoient le numéro de port local et l'adresse de la machine locale (getLocalPort et getLocalAddress), et dans le cas d'un socket connecté, le numéro de port distant et l'adresse distante (getPort et getInetAddress). Comme précédemment, on peut spécifier un délai de garde pour l'opération receive avec setSoTimeout. On peut aussi obtenir ou réduire la taille maximale d'un paquet avec getSendBufferSize, getReceiveBufferSize, setSendBufferSize et setReceiveBufferSize.
Enfin, n'oublions pas la méthode close qui libère les ressources du système associées au socket.