Sockets TCP
Le modèle client/serveur
Le protocole TCP offre un service en mode connecté et fiable. Les données sont délivrées dans l’ordre de leur émission. La procédure d’établissement de connexion est dissymétrique. Un processus, appelé serveur, attends des demandes de connexion qu’un processus, appelé client, lui envoie. Une fois l’étape d’établissement de connexion effectuée le fonctionnement redeviens symétrique. Les deux schémas suivants présentent les algorithmes de fonctionnement des clients et serveurs. Il est à noter que côté serveur on utilise deux sockets : l’un, appelé socket d’écoute, reçoit les demandes de connexion et l’autre, appelé socket de service, sert pour la communication. En effet, un serveur peut être connecté simultanément avec plusieurs clients et dans ce cas on utilisera autant de sockets de service que de clients.
La classe Socket
La classe Socket représente en Java les sockets utilisés côtés client ou les sockets de service. Constructeurs
public Socket (String hote, int port) throws UnknownHostException, IOException
Ce constructeur crée un socket TCP et tente de se connecter sur le port indiqué de l’hôte visé. Le premier paramètre de ce constructeur représente le nom de la machine serveur. Si l’hôte est inconnu ou que le serveur de noms de domaine est inopérant, le constructeur générera une UnknownHostException. Les autres causes d’échec, qui déclenchent l’envoi d’une IOException sont multiples : machine cible refusant la connexion sur le port précisé ou sur tous les ports, problème lié à la connexion Internet, erreur de routage des paquets…
Voici un exemple d’utilisation de ce constructeur : Socket leSocket = new Socket(« www.irit.fr », 80);
public Socket (InetAddress addresse, int port) throws IOException Ce constructeur fonctionne comme le premier, mais prends comme premier paramètre une instance de la classe InetAddress. Ce constructeur provoque une IOException lorsque la tentative de connexion échoue mais il ne renvoie pas d’UnknownHostException puisque cette information est connue lors de la création de l’objet InetAddress.
public Socket(String hote, int port, InetAddress addresseLocale, int portLocal) throws IOException
Comme les deux précédents, ce constructeur crée un socket et tente de se connecter sur le port indiqué de l’hôte visé. Le numéro du port et le nom de la machine sont fournis dans les deux premiers paramètres et la connexion s’établit à partir de l’interface réseau physique (choix d’une carte réseau sur un système possédant plusieurs accès réseau) ou virtuelle (système multi-adresse) et du port local indiqués dans les deux derniers paramètres. Si portLocal vaut 0, la méthode (comme les deux premières d’ailleurs) choisit un port disponible (parfois appelé port anonyme) compris entre 1024 et 65 535. Comme la première méthode cette méthode peut générer une IOException en cas de problème de connexion et lorsque le nom d’hôte donné n’est pas correct (il s’agit dans ce cas d’une UnknownHostException).
public Socket(InetAddress address, int port, InetAddress addresseLocale, int portLocal) throws IOException
Cette méthode est identique à la précédente à la seule différence que le premier paramètre est, comme pour la seconde méthode, un objet InetAddress.
protected Socket() protected Socket(SocketImpl impl) throws SocketException
Ces deux derniers constructeurs sont protégés. Ils créent un socket sans le connecter. On utilise ces constructeurs pour implanter un socket original qui permettra par exemple de chiffrer les transactions ou d’interagir avec un Proxy.
Il existe de plus deux autres constructeurs qui permettent le choix du protocole via un booléen mais ces méthodes sont dépréciées et ne doivent pas être utilisées. Pour créer un socket utilisant UDP on utilisera DatagramSocket.
Méthodes informatives
public InetAddress getInetAddress () public int getPort ()
Ces méthodes renvoient l’adresse Internet et le port distants auquel le socket est connecté.
public InetAddress getLocalAddress () public int getLocalPort ()
Ces méthodes renvoient l’adresse Internet et le port locaux que le socket utilise. 5.2.3. Communication avec un socket
public InputStream getInputStream () throws IOException
Cette méthode renvoie un flux d’entrées brutes grâce auquel un programme peut lire des informations à partir d’un socket. Il est d’usage de lier cet InputStream à un autre flux offrant d’avantage de fonctionnalités (un DataInputStream par exemple) avant d’acquérir les entrées.
Voici un exemple d’utilisation de cette méthode : DataInputStream fluxEnEntree = new DataInputStream(leSocket.getInputStream());
public OutputStream getOutputStream () throws IOException
Cette méthode renvoie un flux de sortie brutes grâce auquel un programme peut écrire des informations sur un socket. Il est d’usage de lier cet OutputStream à un autre flux offrant d’avantage de fonctionnalités (un DataOutputStream par exemple) avant d’émettre des données.
Voici un exemple d’utilisation de cette méthode : DataOutputStream fluxEnSortie = new DataOutputStream(leSocket.getOutputStream());
Fermeture d’un socket
public void close() throws IOException
Bien que Java ferme tous les sockets ouverts lorsqu’un programme se termine ou bien lors d’un « garbage collect », il est fortement conseillé de fermer explicitement les sockets dont on n’a plus besoin à l’aide de la méthode close.
Une fois un socket fermé on peut toujours utiliser les méthodes informatives, par contre toute tentative de lecture ou écriture sur les « input/output streams » provoque une IOException. 5.2.5. Options des sockets
Java permet l’accès à un certain nombre d’options qui modifient le comportement par défaut des sockets. Ces options correspondent à celles que l’on manipule en C via ioctl (ou ioctlsocket avec Windows).
public boolean getTcpNoDelay() throws SocketException public void setTcpNoDelay(boolean valide) throws SocketException
Valide/invalide l’option TCP_NODELAY. Valider TCP_NODELAY garantit que les données seront expédiés aussi rapidement que possible quelle que soit leur taille. Ceci correspond à interdire la mise en œuvre de l’algorithme de Nagle qui, en simplifiant, concatène les données de taille réduite dans des segments de taille supérieure avant envoi. Si l’on programme une application très interactive on pourra valider l’option TCP_NODELAY.
public int getSoLinger() throws SocketException public void setSoLinger(boolean valide, int secondes) throws SocketException
L’option SO_LINGER indique le comportement à adopter lorsqu’il reste des données à expédier au moment de la fermeture du socket. Par défaut, la méthode close() rend la main immédiatement et le système tente d’envoyer le reliquat de données. Si la durée des prolongations secondes vaut 0 et que valide est à vrai, les éventuelles données restant sont supprimés lorsque la fermeture à lieu. Si la durée est positive et que valide est à vrai, la méthode close se fige pendant le nombre de secondes spécifiées en attendant l’expédition des données et la réception de l’acquittement. Une fois les prolongations écoulées, le socket est clos et les données restantes ne sont pas transmises. Si cette option n’est pas validée (valide est à faux) on obtient le comportement par défaut et l’appel de la méthode getSoLinger() retourne –1, sinon la méthode renvoie la durée des prolongations.
public int getSoTimeout() throws SocketException public void setSoTimeout(int ms) throws SocketException
Par défaut, lors d’une tentative de lecture sur le flux d’entrée d’un socket, read() se bloque jusqu’à la réception d’un nombre d’octets suffisant. Lorsque SO_TIMEOUT est initialisée, cette attente ne dépasse pas le temps imparti, exprimé en millisecondes. Tout dépassement de temps se solde par une une java.net.SocketTimeoutException. Le socket reste malgré tout connecté. La valeur par défaut est 0 qui signifie, ici, un laps de temps infini. Il peut être préférable de choisir une durée raisonnable (>0) pour éviter que le programme se bloque en cas de problème. L’option doit être validée avant l’appel à l’opération bloquante pour être prise en compte. Le paramètre doit être >= 0 sans quoi une exception SocketException est générée.
public int getSendBufferSize() throws SocketException public void setSendBufferSize(int size) throws SocketException public int getReceiveBufferSize() throws SocketException public void setReceiveBufferSize(int size) throws SocketException
Ces méthodes permettent, grâce aux options SO_SNDBUF et SO_RCVBUF, de préciser une indication sur la taille à allouer aux tampons d’entrée/sortie bas niveaux. Il s’agit uniquement d’une indication donc il est conseillé après l’appel d’une méthode set… d’appeler la méthode get… correspondante pour vérifier la taille allouée.
La classe ServerSocket
Cette classe permet de créer des sockets qui attendent des connections sur un port spécifié et lors d’une connexion retournent un Socket qui permet de communiquer avec l’appelant.
Constructeurs public ServerSocket (int port) throws IOException
Ce constructeur crée un socket serveur qui attendra les connexions sur le port spécifié. Lorsque l’entier port vaut 0, le port est sélectionné par le système. Ces ports anonymes sont peu utilisés car le client doit connaître à l’avance le numéro du port de destination. Il faut donc un mécanisme, comme le portmapper des RPC, qui permet d’obtenir ce numéro de port à partir d’une autre information. L’echec de la création se solde par une IOException (ou à partir de Java 1.1 une BindException qui hérite de IOException) qui traduit soit l’indisponibilité du port choisi soit, sous UNIX, un problème de droits (sous UNIX les ports inférieurs à 1024 ne sont disponibles que pour le super utilisateur).
public ServerSocket (int port, int tailleFile) throws IOException
Ce constructeur permet en outre de préciser la longueur de la file d’attente des requêtes de connexion. Si une demande de connexion arrive et que la file est pleine la connexion sera refusée sinon elle sera stockée dans la file pour être traitée ultérieurement. La longueur de la file d’attente par défaut (pour le premier constructeur) est 50. Lorsque la valeur donnée est supérieure à la limite fixée par le système, la taille maximale est affectée à la file.
public ServerSocket (int port, int tailleFile, InetAddress adresseLocale) throws IOException
Ce constructeur permet en outre de préciser l’adresse Internet locale sur laquelle attendre des connexions. Ainsi on pourra choisir l’une des interfaces réseau de la machine locale si elle en possède plusieurs. Si adresseLocale est à null le socket attendra des connexions sur toutes les adresses locales (ce qui est aussi le cas quand on utilise l’un des deux autres constructeurs).
Accepter et clore une connexion public Socket accept () throws IOException
Cette méthode bloque l’exécution du programme serveur dans l’attente d’une demande de connexion d’un client. Elle renvoie un objet Socket une fois la connexion établie. Si vous ne voulez pas bloquer l’exécution du programme il suffit de placer l’appel à accept dans un thread spécifique.
super cours moi je l’aime