MulticastDiscussion.java

package fr.umlv.ji.udp;
import java.net.*;
import java.io.*;
import java.util.logging.*;
/**
 * Application réalisant un participant à un groupe de discussion, mis
 * en oeuvre par un groupe de multicast UDP.
 */
public class MulticastDiscussion implements Runnable {
  // Taille maximale des données envoyées
  final static int MAX_DATA_SIZE = 64;
  // Adresse Internet et port du groupe de multicast UDP 
  InetAddress address;
  int port;
  // Socket multicast pour émettre et recevoir les données du groupe
  MulticastSocket socket;
  
  public static void main(String[] args)
    throws Exception {
    if (args.length!=3) {
      System.err.println("Usage: java fr.umlv.ji.udp.MulticastDiscussion "
             +"addr port ttl");
      return;
    }
    MulticastDiscussion discussion =
      new MulticastDiscussion(InetAddress.getByName(args[0]),
                  Integer.parseInt(args[1]),
                  Integer.parseInt(args[2]));
    discussion.start();
  }
  /**
   * Constructeur de l'application de discussion qui s'attache à
   * l'adresse Internet du groupe de multicast IP et au port UDP
   * passés en argument. La socket de multicast UDP reçoit une durée
   * de vie passée en argument.
   */
  public MulticastDiscussion(InetAddress address, int port, int ttl)
    throws IOException {
    this.address = address;
    this.port = port;
    // La socket est attachée au port de multicast UDP 
    socket = new MulticastSocket(port);
    // La durée de vie de la socket est renseignée
    socket.setTimeToLive(ttl);
    // L'application (de la socket) rejoint le groupe de multicast UDP
    socket.joinGroup(address);
  }
  /**
   * Démarre l'application de discussion qui envoie vers le groupe
   * de multicast les lignes lues sur l'entrée standard et écrit sur
   * la sortie standard les lignes reçues depuis le groupe de multicast.
   * La réception et l'affichage sont pris en charge par un processus
   * léger "daemon" qui est démarré et s'exécute en concurrence avec la
   * lecture et l'envoi.
   */
  public void start() throws IOException  {
    // Création et démarrage d'un processus léger daemon qui va exécuter
    // la méthode run pour gérer la réception et l'affichage
    Thread t = new Thread(this);
    t.setDaemon(true);
    t.start();
    // Flot en lecture sur l'entrée standard 
    BufferedReader reader =
      new BufferedReader(new InputStreamReader(System.in));
    String line;
    byte[] buffer = new byte[0];
    int len;
    // Datagramme pour émettre sur le groupe de multicast
    DatagramPacket datag = new DatagramPacket(buffer,0,address,port);
    while ((line = reader.readLine()) != null) {
      // Utilisation d'un codage commun, indépendant de
      // la plate-forme, pour tous les textes lus et écrits
      buffer = line.getBytes("8859_1");
      // Envoi du texte par portions de MAX_DATA_SIZE
      for (int offset=0; offset<buffer.length; offset+=MAX_DATA_SIZE) {
    len = Math.min(buffer.length-offset, MAX_DATA_SIZE);
    datag.setData(buffer, offset, len);
    socket.send(datag);
      }
    }
    socket.leaveGroup(address);
    socket.close();
  }
  /**
   * Code à exécuter par le processus léger pour effectuer la réception
   * du texte du groupe de discussion et son affichage sur la sortie
   * standard.
   */
  public void run() {
    try {
      // Zone de stockage
      byte[] buffer = new byte[MAX_DATA_SIZE];
      // Datagramme de réception
      DatagramPacket datag = new DatagramPacket(buffer,buffer.length);
      // En permanence, afficher ce qu'on reçoit
      while (true) {
    datag.setLength(MAX_DATA_SIZE);
    socket.receive(datag);
    System.out.println(datag.getAddress().getCanonicalHostName() +
      " dit:\n\t" + new String(buffer,0, datag.getLength(),"8859_1"));
      }
    } catch (Exception e){
      e.printStackTrace();
    }
  }
}