:: Enseignements :: Master :: M1 :: 2008-2009 :: Architecture et Programmation Réseau ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
UDP, client/server, DatagramSocket, DatagramChannel, MulticastSocket
|
Les adresses de socket
Une socket identifie un point d'attachement à une machine. Selon le protocole, des classes sont
dédiées pour représenter ces objets :
- java.net.DatagramSocket pour UDP
- java.net.Socket pour TCP
Les adresses de sockets identifient ces points d'attachement indépendamment du protocole :
java.net.SocketAddress (classe abstraite). A priori indépendant du protocole réseau, mais la seule
classe concrète est dédiée aux adresses Internet (IP) : java.net.InetSocketAddress.
Le rôle des sockets
Pour UDP et TCP, les sockets jouent le même rôle et sont identifiées par une adresse IP et un numéro
de port. Au moins 2 sockets sont impliquées dans une communication.
Classe InetSocketAddress
Trois constructeurs :
- InetSocketAddress(InetAddress addr, int port) (si addr est null,
la socket est liée à l'adresse wildcard (non spécifiée) ;
- InetSocketAddress(int port) (l'adresse
IP est l'@ wildcard) ;
- InetSocketAddress(String hostName, int port) (si hostName non résolu,
l'adresse de socket est marquée comme étant non résolue ; peut être testé grâce à la méthode
isUnresolved()).
Les Datagrammes
Les données circulent sur Internet sous forme de datagrammes (on parle aussi de paquets ). Les
datagrammes sont des données encapsulées, c'est-à-dire des données auxquelles on a ajouté des en-têtes
correspondant à des informations sur leur transport (telles que l'adresse IP de destination).
Les données contenues dans les datagrammes sont analysées (et éventuellement modifiées) par les
routeurs permettant leur transit.
La taille max des données transportées est de (216 − 1 − 8). Le Checksum est optionnel en IP v4,
mais obligatoire en IP v6. Voici ce à quoi ressemble un datagramme :
Créer un DatagramSocket
Représente un objet permettant d'envoyer ou recevoir des datagrammes UDP. Il existent différents
constructeurs acceptant des arguments : InetSocketAddress (@IP+port, éventuellement wildcard)
Les méthodes getLocalPort(), getLocalAddress() et getLocalSocketAddress() retournent les
infos sur la socket attachée localement (numéro de port, InetAddress et InetSocketAddress locaux).
La méthode bind(SocketAddress) attache la socket si elle ne l'est pas déjà (isBound() retourne
false). La méthode close() ferme la socket (libère les ressources système associées). isClosed()
permet de savoir si la socket est fermée.
Créer un DatagramPacket
Représente un objet spécifiant les données qui doivent transiter ainsi que l'interlocuteur. Un objet,
deux usages :
- En émission, le DatagramPacket spécifie les données à envoyer et la machine (et le port) vers
qui les envoyer
- En réception, le DatagramPacket spécifie la zone de données permettant de recevoir et mettra
à jour, lors de la réception, la machine et le port depuis lesquels ces données ont été reçues
Un DatagramPacket est fourni à (et pris en charge par) un DatagramSocket,
pour émettre (datagramSocket.send(datagramPacket);) ou pour recevoir
(datagramSocket.receive(datagramPacket); - appel bloquant tant que rien n'est reçu)
Quelques précisions
Les données reçues au delà de la taille de la zone de stockage sont perdues. Le système peut fixer des
tailles des tampons de réception et d'émission. On peut demander à les changer, sans garantie de succès
([get/set]ReceiveBufferSize() et [get/set]SendBufferSize()). Il y a un risque de perte de da-
tagramme : on peut vouloir limiter l'attente en réception (socket.setSoTimeout(int milliseconds)
interrompt l'attente de réception au delà de milliseconds) ; ce qui lève alors une exception
SocketTimeoutException.
User Datagram Protocol
User Datagram Protocol (ou UDP, protocole de datagramme utilisateur) est un des principaux
protocoles de télécommunication utilisé par Internet.
Le rôle de ce protocole est de permettre la transmission de paquets (aussi appelés datagrammes )
de manière très simple entre deux entités, chacune étant définie par une adresse IP et un numéro
de port (pour différencier différents utilisateurs sur la même machine). Contrairement au protocole
TCP, il travaille en mode non-connecté : il n'y a pas de moyen de vérifier si tous les paquets envoyés
sont bien arrivés à destination et ni dans quel ordre. C'est pour cela qu'il est souvent décrit comme
étant un protocole non-fiable. Par contre, pour un datagramme UDP donné, l'exactitude du contenu
des données est assuré grâce à une somme de contrôle (checksum ).
Structure d'un datagramme UDP
Le paquet UDP est encapsulé dans un paquet IP. Il comporte un en-tête suivi des données propre-
ment dites à transporter.
L'en-tête (header en anglais) d'un datagramme UDP est bien plus simple que celui de TCP :
Il contient les 4 champs suivants :
- Port Source : il indique depuis quel port le paquet a été envoyé.
- Port de Destination : il indique à quel port le paquet doit être envoyé
- Longueur : il indique la longueur totale du datagramme UDP (en-tête et données). La longueur
minimale est donc de 8 octets (taille de l'en-tête)
- Somme de contrôle : celle-ci (CRC, Cyclic Redundancy Check ) permet de s'assurer de l'intégrité
du paquet reçu. Elle est calculée sur l'ensemble de l'en-tête UDP et des données, mais aussi sur
un pseudo en-tête (extrait de l'en-tête IP)
Utilisation
Il est utilisé quand il est nécessaire soit de transmettre des données très rapidement, et où la
perte d'une partie de ces données n'a pas grande importance, soit de transmettre des petites quantités de données, là où la connexion 3-WAY TCP serait trop lourde. Par exemple, dans le cas de la
transmission de la voix sur IP, ce n'est pas grave si l'un ou l'autre paquet se perd (il existe des
mécanismes de substitution des données manquante), par contre la rapidité de transmission est un
critère primordial pour la qualité d'écoute.
Exemples d'utilisation : le programme traceroute, les protocoles DNS, TFTP, les jeux en réseau
(exemple : jeux de tir subjectifs), le streaming : il est indispensable pour des applications multimédias
de par sa faible latence.
Liens Externes
RFC 768 : User Datagram Protocol : http ://www.ietf.org/rfc/rfc768.txt
IANA Port Assignments : liste des ports prédéfinis et de leurs utilisations, par l'IANA :
http ://www.iana.org/assignments/port-numbers
Communications Client/Serveur en UDP
Exemple de Client utilisant IO :
Exemple de Serveur utilisant IO :
Exemple de Client utilisant NIO (Channel) :
Exemple de Serveur utilisant NIO (Channel) :
Accès à UDP via les canaux
La classe java.nio.channels.DatagramChannel permet de créer un Canal vers une socket UDP.
On peut créer une java.net.DatagramSocket à partir d'un DatagramChannel, mais pas le contraire.
Si une socket UDP su a été créée à partir d'un canal, on peut récupérer ce dernier par su.getChannel().
Sinon, cette méthode retourne null. La méthode DatagramChannel.open() crée et retourne un canal
associé à une socket UDP (non attachée). DatagramChannel n'est pas une abstraction complète des
sockets UDP : pour les opérations précises (binding, etc...) on récupère l'objet DatagramSocket sous-
jacent.
DatagramChannel
Par défaut, un canal dc récupéré par DatagramChannel.open() est bloquant. Il peut être configuré non bloquant. dc.socket() récupère alors la DatagramSocket correspondante. Elle n'est pas
attachée. On peut faire bind(SocketAddress) sur cette socket. Les méthodes send() et receive()
sont accessibles depuis le canal. Elles manipulent des ByteBuffer et receive() retourne un objet
SocketAddress identifiant l'émetteur des données reçues. On doit faire une pseudo-connexion pour
pouvoir utiliser les méthodes read() et write() avec des ByteBuffer, plus classiques sur les canaux
(interlocuteur implicite pour ces méthodes).
Envoi sur un DatagramChannel
int send(ByteBuffer src, SocketAddress target) provoque l'envoi des données restantes du
tampon src vers target (semblable à un write() du point de vue du canal). Si canal bloquant, la
méthode retourne lorsque tous les octets ont été émis (leur nombre est retourné). Si canal non bloquant,
la méthode émet tous les octets ou aucun. Si une autre écriture est en cours sur la socket par une
autre thread, l'invocation de cette méthode bloque jusqu'à ce que la première opération soit terminée.
Réception depuis un DatagramChannel
SocketAddress receive(ByteBuffer dst) est, par défaut, une méthode bloquante tant que rien
n'est reçu par la socket. Au plus dst.remaining() octets peuvent être reçus ; le reste est tronqué. Cette
méthode retourne l'adresse de socket (IP+port) de l'émetteur des données. Si canal non bloquant, soit
tout est reçu, soit le tampon n'est pas modifié et la méthode retourne null.
Exemple de client UDP avec canaux : envoi
Exemple de client UDP avec canaux : réception
Exemple d'émission (client)
Exemple de réception (client)
Exemple de réception (serveur)
Dans le cas d'un client, le choix du numéro de port d'attachement de la socket n'a pas d'importance,
il sera connu par le serveur à la réception du datagramme émis par le client. En revanche, dans le
cas d'un serveur, il doit pouvoir être communiqué aux clients, afin qu'ils puissent l'interroger. Il est
nécessaire d'attacher la socket d'écoute (d'attente des clients) à un port et une adresse spécifique et
connue ainsi que d'utiliser un constructeur de DatagramSocket le spécifiant (il y a un risque que le
port ne soit pas libre : SocketException).
Réception serveur (suite)
Broadcast et Multicast
Le broadcast est un terme anglais (en français on utilise le terme diffusion) définissant une
diffusion de données à un ensemble d'ordinateurs connectés à un réseau informatique. Les protocoles de
communications réseau prévoient une méthode simple pour diffuser des données à plusieurs machines
en même temps. Au contraire d'une communication Point à Point (unicast), il est possible
d'adresser des paquets de données à un ensemble de machines d'un même réseau uniquement par des
adresses spécifiques qui seront interceptées par toutes les machines du réseau ou sous-réseau.
L'étendue de diffusion sera restreinte au domaine de diffusion. Par exemple, en IPv4, une adresse
IP de diffusion telle que 192.168.1.255 sera interceptée par toutes les machines ayant une adresse IP
entre 192.168.1.1 et 192.168.1.254, pour autant que le masque de sous-réseau de l'interface soit
défini comme 255.255.255.0.
Un commutateur recevant une trame broadcast sur l'un de ses ports la diffusera sur tous les autres
ports. Les routeurs ne transmettent pas les paquets broadcast.
Pour une diffusion de données moins générale, on utilisera les adresses Multicast
On entend par multicast le fait de communiquer simultanément avec un groupe d'ordinateurs
identifiés par une adresse spécifique (adresse de groupe).
Communication en diffusion
D'un émetteur vers un groupe ou un ensemble de récepteurs :
- le broadcast utilise les mêmes classes DatagramSocket et DatagramPacket que pour la commu-
nication unicast, avec une adresse destination de broadcast
- le multicast utilise la classe DatagramPacket pour les datagrammes mais la classe
MulticastSocket, spécifique pour les sockets
Le broadcast
La classe DatagramSocket dispose de méthodes [set/get]Broadcast() (autorisation pour la
socket d'émettre des broadcasts). En réception, une socket ne peut recevoir des broadcasts que si elle
est attachée à l'adresse non spécifiée (wildcard).
Le multicast
On s'adresse à un ensemble de machines (ou applications) ayant explicitement adhéré au groupe
(adresses de classe D en IP v4 : 224.0.0.0/4, adresses du réseau FF00 : :/8 en IP v6). Les machines
ayant rejoint un tel groupe acceptent les datagrammes à destination de l'adresse correspondante.
java.net.MulticastSocket
Cette classe hérite de DatagramSocket. Elle possèdent trois constructeurs de MulticastSocket :
sans arguments : attache à un port libre et à l'@ wildcard ; numéro de port : attache à ce port et à
l'@ wildcard ; SocketAddress : attache à cette adresse de socket, ou bien n'attache pas la socket si
l'argument vaut null.
Les constructeurs appellent la méthode setReuseAddress(true) qui autorise plusieurs sockets à
s'attacher à la même adresse (MÊME PORT pour tous les membres du groupe).
MulticastSocket en émission
En émission, MulticastSocket s'utilise comme DatagramSocket. On peut spécifier une durée
de vie pour le datagramme : plus exactement, un nombre de sauts (0=émetteur, 1=réseau local,
16= site, 32=région, 48=pays, 64=continent, 128=monde).
MulticastSocket en réception
Il faut explicitement rejoindre le groupe (joinGroup() avec l'adresse IP multicast du groupe en
argument (existe aussi avec SocketAddress et/ou NetworkInterface). Cela permet alors à la socket
de recevoir tous les datagrammes destinés à cette adresse multicast. On peut rejoindre plusieurs
groupes de multicast. La méthode leaveGroup() permet de quitter le groupe d'adresse spécifiée en
argument.
© Université de Marne-la-Vallée