Bon, un post un peu technique... Je ne puis résister au plaisir de vous livrer ce petit morceau de code (un petit programme java de 150 lignes en tout, composé de 2 fichiers : un client, et un serveur).

Il s'agit d'un exemple (assez basique) de système d'échange de fichiers en "peer-to-peer" (ou P2P).

Principes :
- Clients et serveurs disposent d'une liste d'adresses IP de serveurs connus (dans un fichier nommé "servers.list").
- Le client lance une requête spécifiant un nom de fichier à télécharger.
- Cette requête est transmise aux serveurs que le client connaît
- Lorsqu'un serveur reçoit une requête, il renvoie le fichier demandé s'il le détient, et sinon réémet la requête vers les autres serveurs qu'il connaît, etc... (la profondeur étant limitée à 3 serveurs, sinon les réémissions pourraient se poursuivre à l'infini).
- Dés que le fichier demandé est trouvé quelque part, il est ramené vers le client (via la chaîne d'appels) et la recherche s'arrête.
- Le serveur est multiprogrammé (exécution possible de plusieurs requêtes en parallèle, en utilisant des "threads").

Evidemment, je précise (pour être conforme à la loi DADVSI) que ce programme n'est absolument pas dédié à échanger des oeuvres protégées par le droit d'auteur (l'utiliser dans ce but serait donc un détournement manifeste de l'objectif dans lequel il a été conçu, à savoir comme exemple de programmation à visée pédagogique - pour que tout le monde puisse découvrir les bases de ce type de programmation).

De fait, il serait sans doute un peu trop limité pour un tel usage (ou bien inefficace, en regard de ce qui existe sur le web !), et comporte probablement quelques bugs (j'avoue l'avoir peu testé, juste le minimum), en plus de ne fournir aucune sécurité (qui n'était pas le but de l'exemple).

Quoiqu'il en soit, si quelque héraut de la DADVSI devait s'offusquer, qu'il sache que mes avocats l'attendent, et que j'ai l'heur de pouvoir les payer... De plus, je ne fournis ici que du texte, et pas un programme exécutable (il est donc probable que les lois sur la presse s'appliquent - à savoir droit de réponse ou de recours juridique sous 3 mois aprés publication), tout recours nécessitant de s'assurer auparavant que ce programme peut fonctionner (et d'avoir bien compris à quoi il sert).

Place au code, maintenant... bonne lecture !


//-------------//
// Server.java //
//-------------//


//-------------//
// Server.java //
//-------------//

package p2p;

import java.net.*;
import java.io.*;

public class Server implements Runnable {

  public static void main(String[] args) throws Exception {

    ServerSocket srv = new ServerSocket(1234);

    while(true) {
      Thread t = new Thread(new Server(srv.accept()));
      t.start();
    }
    // srv.close();
  }

  // Client socket in/out streams
  BufferedReader clientInput_;
  OutputStream clientOutput_;

  public Server(Socket client) throws Exception {
    clientInput_ = new BufferedReader(
      new InputStreamReader(client.getInputStream()));
    clientOutput_ = client.getOutputStream();
  }

  public void run() { // Executed upon Thread's start() method call
    try {
      int level = 3;

      // Read "level" information
      // (max depth if further server calls are necessary)
      String line = clientInput_.readLine();
      if(line != null) level = Integer.parseInt(line);

      // Read the name of the requested file
      if((line = clientInput_.readLine()) != null) {
        File f = new File("." + File.separator + line);
        System.out.print("Client request for file " + line + "...");
        if(f.exists()) {
          copyStream(new FileInputStream(f), clientOutput_, true);
          System.out.println(" transfer done.");
        }
        else if(level > 0) { // File is not here... maybe on another server ?
          System.out.println(" file is not here, lookup further...");
          // Lookup on other known servers (decrement depth)
          boolean found = lookupFurther(level-1, line, clientOutput_);
          System.out.println(found ? "Transfer done." : "File not found.");
        }
      }

      clientInput_.close();
      clientOutput_.close();

    } catch(Exception e) { } // ignore
  }

  /*
   * Lookup the requested file on every known server
   * Server list is in local "servers.list" text file (one IP address per line)
   */
  static boolean lookupFurther(int level, String fname, OutputStream out)
  throws IOException {

    BufferedReader hosts;
    try {
      hosts = new BufferedReader(new FileReader("servers.list"));
    } catch(FileNotFoundException e) {
      System.out.println("No servers.list file, can't lookup further !");
      return false;
    }

    String ip;
    boolean found = false;
    while(! found && (ip = hosts.readLine()) != null) {
      System.out.println("trying server " + ip);
      try {
        Socket s = new Socket(ip, 1234);
        PrintWriter srv = new PrintWriter(s.getOutputStream(), true);
        srv.println(level + "\n" + fname);
        int nbytes = copyStream(s.getInputStream(), out, true);
        s.close();
        found = (nbytes > 0);
      } catch(ConnectException e) { } // ignore
    }
    hosts.close();
    return found;
  }

  public static int copyStream(InputStream in, OutputStream out, boolean close)
  throws IOException {
    int nbytes = 0, total = 0;
    byte[] buf = new byte[1024];
    while ((nbytes = in.read(buf)) > 0) {
      out.write(buf, 0, nbytes);
      total += nbytes;
    }
    if(close) in.close();
    return total;
  }
}


//-------------//
// Client.java //
//-------------//

package p2p;

import java.net.*;
import java.io.*;

/*
* Usage: Client <filename>
* Lookup a file across one or more server(s), and bring it here.
* List of server IP addresses should be in local "server.in" text file
* (one IP per line)
*/
public class Client {

  public static void main(String[] args) throws Exception {

    String ip;
    boolean found = false;

    // Loop on servers list (obtained from local "servers.in" file)
    BufferedReader hosts = new BufferedReader(new FileReader("servers.list"));
    while(! found && (ip = hosts.readLine()) != null) {

      Socket s = new Socket(ip, 1234);
      PrintWriter srv = new PrintWriter(s.getOutputStream(), true);

      // Ask for requested file, max depth (calls to further servers) = 3
      srv.println(3 + "\n" + args[0]);

      // Bring back the file, if any
      File f = new File("." + File.separator + args[0]);
      FileOutputStream out = new FileOutputStream(f);
      found = (Server.copyStream(s.getInputStream(), out, true) > 0);
      out.close();
      if(! found) f.delete();

    }
    hosts.close();
  }


//-------------//
// Server.java //
//-------------//

package p2p;

import java.net.*;
import java.io.*;

public class Server implements Runnable {

  public static void main(String[] args) throws Exception {

    ServerSocket srv = new ServerSocket(1234);

    while(true) {
      Thread t = new Thread(new Server(srv.accept()));
      t.start();
    }
    // srv.close();
  }

  // Client socket in/out streams
  BufferedReader clientInput_;
  OutputStream clientOutput_;

  public Server(Socket client) throws Exception {
    clientInput_ = new BufferedReader(
      new InputStreamReader(client.getInputStream()));
    clientOutput_ = client.getOutputStream();
  }

  public void run() { // Executed upon Thread's start() method call
    try {
      int level = 3;

      // Read "level" information
      // (max depth if further server calls are necessary)
      String line = clientInput_.readLine();
      if(line != null) level = Integer.parseInt(line);

      // Read the name of the requested file
      if((line = clientInput_.readLine()) != null) {
        File f = new File("." + File.separator + line);
        System.out.print("Client request for file " + line + "...");
        if(f.exists()) {
          copyStream(new FileInputStream(f), clientOutput_, true);
          System.out.println(" transfer done.");
        }
        else if(level > 0) { // File is not here... maybe on another server ?
          System.out.println(" file is not here, lookup further...");
          // Lookup on other known servers (decrement depth)
          boolean found = lookupFurther(level-1, line, clientOutput_);
          System.out.println(found ? "Transfer done." : "File not found.");
        }
      }

      clientInput_.close();
      clientOutput_.close();

    } catch(Exception e) { } // ignore
  }

  /*
   * Lookup the requested file on every known server
   * Server list is in local "servers.list" text file (one IP address per line)
   */
  static boolean lookupFurther(int level, String fname, OutputStream out)
  throws IOException {

    BufferedReader hosts;
    try {
      hosts = new BufferedReader(new FileReader("servers.list"));
    } catch(FileNotFoundException e) {
      System.out.println("No servers.list file, can't lookup further !");
      return false;
    }

    String ip;
    boolean found = false;
    while(! found && (ip = hosts.readLine()) != null) {
      System.out.println("trying server " + ip);
      try {
        Socket s = new Socket(ip, 1234);
        PrintWriter srv = new PrintWriter(s.getOutputStream(), true);
        srv.println(level + "\n" + fname);
        int nbytes = copyStream(s.getInputStream(), out, true);
        s.close();
        found = (nbytes > 0);
      } catch(ConnectException e) { } // ignore
    }
    hosts.close();
    return found;
  }

  public static int copyStream(InputStream in, OutputStream out, boolean close)
  throws IOException {
    int nbytes = 0, total = 0;
    byte[] buf = new byte[1024];
    while ((nbytes = in.read(buf)) > 0) {
      out.write(buf, 0, nbytes);
      total += nbytes;
    }
    if(close) in.close();
    return total;
  }
}


//-------------//
// Client.java //
//-------------//

package p2p;

import java.net.*;
import java.io.*;

/*
* Usage: Client <filename>
* Lookup a file across one or more server(s), and bring it here.
* List of server IP addresses should be in local "server.in" text file
* (one IP per line)
*/
public class Client {

  public static void main(String[] args) throws Exception {

    String ip;
    boolean found = false;

    // Loop on servers list (obtained from local "servers.in" file)
    BufferedReader hosts = new BufferedReader(new FileReader("servers.list"));
    while(! found && (ip = hosts.readLine()) != null) {

      Socket s = new Socket(ip, 1234);
      PrintWriter srv = new PrintWriter(s.getOutputStream(), true);

      // Ask for requested file, max depth (calls to further servers) = 3
      srv.println(3 + "\n" + args[0]);

      // Bring back the file, if any
      File f = new File("." + File.separator + args[0]);
      FileOutputStream out = new FileOutputStream(f);
      found = (Server.copyStream(s.getInputStream(), out, true) > 0);
      out.close();
      if(! found) f.delete();

    }
    hosts.close();
  }

}
}
package p2p;

import java.net.*;
import java.io.*;

public class Server implements Runnable {

  public static void main(String[] args) throws Exception {

    ServerSocket srv = new ServerSocket(1234);

    while(true) {
      Thread t = new Thread(new Server(srv.accept()));
      t.start();
    }
    // srv.close();
  }

  // Client socket in/out streams
  BufferedReader clientInput_;
  OutputStream clientOutput_;

  public Server(Socket client) throws Exception {
    clientInput_ = new BufferedReader(
      new InputStreamReader(client.getInputStream()));
    clientOutput_ = client.getOutputStream();
  }

  public void run() { // Executed upon Thread's start() method call
    try {
      int level = 3;

      // Read "level" information
      // (max depth if further server calls are necessary)
      String line = clientInput_.readLine();
      if(line != null) level = Integer.parseInt(line);

      // Read the name of the requested file
      if((line = clientInput_.readLine()) != null) {
        File f = new File("." + File.separator + line);
        System.out.print("Client request for file " + line + "...");
        if(f.exists()) {
          copyStream(new FileInputStream(f), clientOutput_, true);
          System.out.println(" transfer done.");
        }
        else if(level > 0) { // File is not here... maybe on another server ?
          System.out.println(" file is not here, lookup further...");
          // Lookup on other known servers (decrement depth)
          boolean found = lookupFurther(level-1, line, clientOutput_);
          System.out.println(found ? "Transfer done." : "File not found.");
        }
      }

      clientInput_.close();
      clientOutput_.close();

    } catch(Exception e) { } // ignore
  }

  /*
   * Lookup the requested file on every known server
   * Server list is in local "servers.list" text file (one IP address per line)
   */
  static boolean lookupFurther(int level, String fname, OutputStream out)
  throws IOException {

    BufferedReader hosts;
    try {
      hosts = new BufferedReader(new FileReader("servers.list"));
    } catch(FileNotFoundException e) {
      System.out.println("No servers.list file, can't lookup further !");
      return false;
    }

    String ip;
    boolean found = false;
    while(! found && (ip = hosts.readLine()) != null) {
      System.out.println("trying server " + ip);
      try {
        Socket s = new Socket(ip, 1234);
        PrintWriter srv = new PrintWriter(s.getOutputStream(), true);
        srv.println(level + "\n" + fname);
        int nbytes = copyStream(s.getInputStream(), out, true);
        s.close();
        found = (nbytes > 0);
      } catch(ConnectException e) { } // ignore
    }
    hosts.close();
    return found;
  }

  public static int copyStream(InputStream in, OutputStream out, boolean close)
  throws IOException {
    int nbytes = 0, total = 0;
    byte[] buf = new byte[1024];
    while ((nbytes = in.read(buf)) > 0) {
      out.write(buf, 0, nbytes);
      total += nbytes;
    }
    if(close) in.close();
    return total;
  }
}


//-------------//
// Client.java //
//-------------//

package p2p;

import java.net.*;
import java.io.*;

/*
* Usage: Client <filename>
* Lookup a file across one or more server(s), and bring it here.
* List of server IP addresses should be in local "server.in" text file
* (one IP per line)
*/
public class Client {

  public static void main(String[] args) throws Exception {

    String ip;
    boolean found = false;

    // Loop on servers list (obtained from local "servers.in" file)
    BufferedReader hosts = new BufferedReader(new FileReader("servers.list"));
    while(! found && (ip = hosts.readLine()) != null) {

      Socket s = new Socket(ip, 1234);
      PrintWriter srv = new PrintWriter(s.getOutputStream(), true);

      // Ask for requested file, max depth (calls to further servers) = 3
      srv.println(3 + "\n" + args[0]);

      // Bring back the file, if any
      File f = new File("." + File.separator + args[0]);
      FileOutputStream out = new FileOutputStream(f);
      found = (Server.copyStream(s.getInputStream(), out, true) > 0);
      out.close();
      if(! found) f.delete();

    }
    hosts.close();
  }

}