Université Paris 7 M2 II Protocole Internet Document à rendre: Vous

publicité
Université Paris 7
M2 II
Protocole Internet
TP2
Document à rendre: Vous devez déposer sur didel pour le 3 décembre:
le code java des questions 7, 8 et 9(b) accompagné d’un cours rapport (environ 3 pages) présentant plus particulièrement la description du protocole de la
question 9a et la manière dont vous avez testé votre application (question 10).
Attention à bien respecter le format des messages.
L’objectif de cet exercice est de réaliser une application distribuée pair-àpair en utilisant les sockets UDP en mode diffusion (i.e. permettant l’envoi
d’un message à toutes les machines connectées au réseau en une seule opération
d’envoi).
On veut réaliser une application de discussion multipoint ("chat"). Votre
programme devra envoyer sur les machines participantes de la salle toutes les
lignes lues sur l’entrée standard et afficher sur la sortie standard tous les messages reçus.
On utilise ici la classe MulticastSocket (java.net.MulticastSocket) qui permet
des communications de groupe. Elle permet d’envoyer et de recevoir des paquets
sur l’internet. Un groupe de multicast est identifié par une adresse IP de classe
D et par un port UDP classique. Les adresses de classes D vont de 224.0.0.0 à
239.255.255.255. L’adresse 224.0.0.0 est réservée et ne doit pas être utilisée.
1. Création
Ecrire une classe Com pour l’envoi et la réception de paquets de la discussion. Votre classe contiendra les champs :
int port ; // Le port d’écoute du socket
InetAddress multicastAddress ; // L’adresse IP utilisée pour la communication de groupe.
MulticastSocket socket ; // Le socket identifié par son port
Dans la phase de test vous choisirez le port 66i et l’adresse multicast
230.1.1.i où i est un numéro qui vous sera attribué au début du TP. Pour
réaliser la discussion entre toutes les machines de la salle, vous utiliserez
le port 6666 et l’adresse multicast 230.1.1.66. Dans la suite p désigne le
port et am l’adresse multicast.
2. Ecrire un constructeur qui :
1
• initialise le port à p
• crée le socket par socket = new MulticastSocket (port)
• crée l’adresse multicast par multicastAddress = InetAddress.getByName
("am"),
• indique que le socket va servir à recevoir les paquets à destination de
cette adresse par socket.joinGroup (multicastAddress).
La classe ByteBuffer (java.nio.ByteBuffer) est utilisée pour envoyer et recevoir
des paquets. Un ByteBuffer b manipule de manière interne un tableau d’octets
que l’on obtient par b.array(). On peut obtenir sa capacité par b.capacity(). On
peut de plus lire et écrire à une position courante (obtenue par b.position()) par
des méthodes de type get et put. Les lectures se font jusqu’à une position limite
donnée par b.limit(). La méthode getString suivante sert à lire une String de
longueur connue dans un ByteBuffer:
static String getString (ByteBuffer b, int len) {
byte[] t = new byte[len] ;
b.get (t) ;
return new String (t, 0, len) ;
}
La conversion de String vers byte[] se fait par la méthode getBytes().
3. Ecrire une méthode send() qui prend en argument un ByteBuffer et envoie
son contenu sur le socket par la méthode send de MulticastSocket. Seuls
les octets entre le début du ByteBuffer et sa position courante doivent être
envoyés.
Il faudra pour cela construire un DatagramPacket à partir du ByteBuffer,
de l’adresse am et du port p de destination. Vous pouvez utiliser le constructeur: DatagramPacket(byte[] buf, int length) pour affecter les données et la méthode setSocketAddress(SocketAddress address) pour affecter
l’adresse destination am, et le port p.
4. Ecrire une méthode sendUnicast() qui prend en argument une SocketAddress et un ByteBuffer et envoie son contenu sur le socket par la méthode
send de MulticastSocket. Seuls les octets entre le début du ByteBuffer et
sa position courante doivent être envoyés.
Il faudra pour cela construire un DatagramPacket à partir du ByteBuffer.
Vous pouvez utiliser le constructeur: DatagramPacket(byte[] buf, int length)
pour affecter les données et la méthode setSocketAddress(SocketAddress
address) pour affecter l’adresse destination.
5. Ecrire une méthode receive() qui prend en argument un ByteBuffer, remplit son contenu par celui du paquet reçu et renvoie l’adresse et le port
de l’envoyeur sous forme de SocketAddress. Utiliser pour cela la méthode
receive(DatagramPacket x) de MulticastSocket pour recevoir un paquet.
2
Vous pouvez utiliser le constructeur DatagramPacket(byte[] buf, int length)
pour partager le même tableau de bytes que le ByteBuffer. Mettre ensuite
la position du ByteBuffer à 0 et sa limite à la longueur du DatagramPacket (qui est obtenue par getLength()). Renvoyer l’adresse et le port de
l’envoyeur du paquet obtenus par getSocketAddress().
6. Tester vos méthodes avec le code ci-dessous qui envoie 2 messages constitués des chaines lues dans les arguments du main et un numéro.
import
import
import
import
java.net.InetAddress;
java.net.SocketAddress;
java.net.UnknownHostException;
java.nio.ByteBuffer;
public class Main{
static String getString (ByteBuffer b, int len)
{ byte[] t = new byte[len] ; b.get (t) ; return new String (t, 0, len) ;
}
public static void main (String[] args) {
Com s = new Com(6666);
ByteBuffer b = ByteBuffer.allocate(1400) ;
InetAddress moi;
int i=1;
String msg;
try
{ moi = InetAddress.getLocalHost();
} catch (UnknownHostException ex)
{ moi=null;
}
msg = "envoi de "+ moi.getHostAddress() ;
for (String a : args)
msg += " " + a ;
msg= msg + " " +i;
b.put (msg.getBytes()) ;
s.send (b);
SocketAddress from =s.receive (b); //on recoit son messge (ou un autre)
System.out.println ("reception de " + from + " : " +
getString (b, b.limit())) ;
b.clear();
msg= msg + " message renvoye ";
b.put (msg.getBytes()) ;
s.sendUnicast (from,b);
3
!!
System.out.println ("reception de unicast " + s.receive (b)+ " : " +
getString (b, b.limit())) ;
b.clear();
}
}
Pour pouvoir discuter clairement les uns avec les autres de manière plus
robuste, on utilise un format particulier de message :
ID est un champ indiquant la nature du message (codé sur 2 octets). On
définit dans cette première version
public static short DATA = 1
public static short BEGIN= 2
public static short LAST = 3
surnom identifie l’envoyeur, c’est une suite de 6 lettres (codée sur 6 octets).
seq est un numéro de séquence (sur 2 octets) incrémenté par l’envoyeur chaque
fois qu’il envoie un paquet DATA
taille est la longueur du message qui suit sur 2 octets.
message c’est la suite des caractères du message.
7.
VERSION V0
Le protocole de communication indique que tous les messages de type
DATA correctement formés suivant la description ci-dessus seront affichés
dés qu’ils sont reçus (on ne se préoccupe pas ici de vérifier le champ seq)
et tous les autres seront ignorés.
Ecrire l’application de discussion réalisant le protocole simple de "chat"
avec un thread pour la réception des messages, le thread principal étant
dédié à l’envoi.
8.
VERSION V1
Un nouvel utilisateur arrivant dans la discussion veut pouvoir recevoir le
dernier message envoyé par tous les membres de la discussion. On utilisera
un message de type BEGIN et de type LAST. BEGIN correspond à un nouvel
arrivant et à une demande de réémission. LAST correspond à la réémission
du dernier message envoyé (le champ seq sera alors le numéro de ce message
pour l’émetteur).
Ecrire l’application de discussion réalisant ce protocole enrichi.
4
9.
VERSION V2
On veut maintenant afficher les messages reçus dans l’ordre dans lequel
ils ont été envoyé. I.e. si on a affiché le x ème message d’un utilisateur on
n’affichera ensuite qu’un message de numéro strictement supérieur à x.
Dans une application réelle de discussion sur Internet, des paquets peuvent être perdus ou déséquencés, notamment en cas de congestion dans le
réseau.
(a) Définissez un protocole (en ajoutant de nouveaux types de messages)
pour signaler la perte du message à son émetteur et demander la
réémission des paquets perdus. Lors la définition de ce protocole
vous aurez des choix à faire: quand, à qui demander la réémission
d’un paquet, les champs du paquet demandant la réémission et du
paquet de réponse....
Justifiez les choix que vous avez faits.
(b) Réalisez une application suivant le protocole que vous avez défini.
10. On veut pouvoir tester une application réalisant le protocole de "chat" que
vous avez défini. Ecrire un programme qui permet de tester l’application
(par exemple en introduisant volontairement des pertes des messages et
des déséquencements dans les messages.)
5
Téléchargement