[JAVA] Transfert de fichier par sockets

Résolu
Valryon -  
KX Messages postés 19031 Statut Modérateur -
Bonjour,
Je suis à la recherche de l'algorithme permettant le transfert d'un fichier d'un PC à un autre via l'utilisation de sockets.

J'ai essayé beaucoup de choses. Aucun problèmes pour la création et l'utilisations des cokets.

Ce qui me bloque c'est plutôt comment envoyer un fichier et comment le réceptionner...

Pour le moment j'essaye de faire en sorte que le client envoie au serveur un fichier de son choix.

Côté client :
- Je propose à l'utilisateur le choix d'un fichier quelquonque (pas uniquement texte !)
- Je transforme ce fichier en tableau de Bytes
- J'envoi ce tableau par socket, celle-ci étant connectée à la socket du serveur :

[code]
public static void sendFile(String pathname) throws Exception
{
File f = new File(pathname);

if(f.exists())
{
System.out.println("Envoi du fichier "+f.toURI().toURL());
Socket s = new Socket(InetAddress.getByName(serveur),port);

PrintStream sortie=new PrintStream(s.getOutputStream());

sortie.write(fileToByte(f),0,fileToByte(f).length);

s.close();
}
else
{
System.out.println("Le fichier "+f+" est introuvable");
}

}

[/code]

La méthode FileToByte a été trouvée sur Internet :
[code]
static public byte[] fileToByte(File file) throws IOException {
InputStream in = new BufferedInputStream(new FileInputStream(file));
ByteArrayOutputStream result = new ByteArrayOutputStream();
BufferedOutputStream tmp = new BufferedOutputStream(result);
for (int b=in.read(); b != -1; b=in.read()) {
tmp.write(b);
}
in.close();
tmp.close();

return result.toByteArray();
}
[/code]

Côté Serveur :
- Création de la socket, le serveur attend la connexion des clients
- Si un client veut envoyer un fichier, on récupère... rien d'intéressant. C'est là que je bloque !

[code]
while(continuer)
{
//On attend la connexion d'un client
Socket serviceSocket = serveur.accept();

//Création de l'entrée
InputStream inpute = serviceSocket.getInputStream();
int b = inpute.read();

//On récupère le flux de sortie et d'entrée du client
System.out.println("Reçu : "+b);
... (la suite importe peu)
[/code]

Connaissez-vous le moyen de récupérer le tableau de Bytes transitant par le réseau, puis de l'enregistrer dans un fichier ?
Merci :)

8 réponses

  1. Valryon
     
    Trouvé !
    Le code :

    - côté client
    public static void sendFile(String pathname,String serv) throws Exception
    {
    File f = new File(pathname);
    if(f.exists())
    {
    System.out.println("Envoi du fichier "+f.toURI().toURL());
    Socket s = new Socket(InetAddress.getByName(serv),port);

    OutputStream fluxsortie = s.getOutputStream();

    long taillefichier =f.length();

    System.out.println("Taille : "+ taillefichier);

    long nbpassagesuposé=taillefichier / 4096;

    System.out.println("Passages supposés : "+nbpassagesuposé);

    InputStream in = new BufferedInputStream(new FileInputStream(f));
    ByteArrayOutputStream tableaubytes = new ByteArrayOutputStream();
    BufferedOutputStream tampon = new BufferedOutputStream(tableaubytes);

    int lu = in.read();
    int[] aecrire = new int[4096];
    int compteur = 0;
    long ouonestrendu=0;

    //Tant qu'on est pas à la fin fu chier
    while(lu > -1)
    {
    //On lit les données du fichier
    aecrire[compteur] = lu;
    lu = in.read();
    compteur++;

    //Quand on a rempli le tableau, on envoie un paquet de 4096 octets
    if(compteur == 4096)
    {
    compteur=0;
    ouonestrendu++;
    //On remplit le tampon
    for(int x=0;x<4096;x++)
    tampon.write(aecrire[x]);

    //Et on l'envoie
    fluxsortie.write(tableaubytes.toByteArray());

    tableaubytes.reset();
    System.out.println("Avancement : "+(float) ouonestrendu/nbpassagesuposé * 100+"%");
    }
    }

    //On envoie le dernier paquet, qui ne fait pas forcément 4096 octets
    //On remplit le tampon
    for(int x=0;x<4096;x++)
    tampon.write(aecrire[x]);

    //Et on l'envoie
    tampon.flush();
    fluxsortie.write(tableaubytes.toByteArray());
    fluxsortie.flush();

    System.out.println("Avancement: "+(float) ouonestrendu/nbpassagesuposé * 100+"%");

    System.out.println("Youpi finished");
    in.close();
    tampon.close();
    System.out.println("Passages effectués : "+ouonestrendu);
    s.close();
    }
    else
    {
    System.out.println("Le fichier "+f+" est introuvable");
    }

    }

    - serveur :

    while(continuer)
    {
    //On attend la connexion d'un client
    Socket serviceSocket = serveur.accept();

    Byte[] taillefichier;
    int lu;
    long taille = 0;

    //Création de l'entrée
    InputStream inpute = serviceSocket.getInputStream();

    OutputStream out = new FileOutputStream("D:\\lol.ha");

    //Reçoit du client
    BufferedInputStream inBuffer = new BufferedInputStream(inpute);

    //Envoi vers le fichier
    BufferedOutputStream outBuffer = new BufferedOutputStream(out);

    lu = inBuffer.read();

    int compteur = 0;

    while(lu > -1)
    {
    outBuffer.write(lu);
    lu = inBuffer.read();

    compteur++;
    }

    outBuffer.write(lu);

    outBuffer.flush();
    outBuffer.close();
    inBuffer.close();

    out.flush();
    out.close();
    inpute.close();
    serviceSocket.close();

    }
    23
    1. DjSKeud Messages postés 103 Statut Membre 31
       
      ...cool, c'est "tampon.flush();" qui à solutionné ton problème ?
      0
    2. OuiOui
       
      Salut Valryon,

      Merci pour le code, je viens de l'utiliser.
      Je pense qu'il y avait un petit problème dans le code client.
      Pour le dernier paquet tu remplit quand même le tampon avec 4096:

      //On envoie le dernier paquet, qui ne fait pas forcément 4096 octets
      //On remplit le tampon
      for(int x=0;x<4096;x++)
      tampon.write(aecrire[x]);

      Alors que aecrire ne comptient pas 4096 byte pertinent. Il en contient le nombre "compteur" de la boucle while du dessus. Je propose donc:

      //On envoie le dernier paquet, qui ne fait pas forcément 4096 octets
      //On remplit le tampon
      for(int x=0;x<compteur;x++)
      tampon.write(aecrire[x]);

      Le reste marche bien pour moi, merci.

      OuiOui
      0
    3. vanrostand
       
      slt,; moi je ss debutant en java. mais deja tn programme m'interesse beaucoup. Seulement je ne compreend pas un truc:

      cote client: tes variables d'entrees.sont- elles standard?
      coté serveur: lorsque je declarer le serveur (coe ci dessous) j'obtiens une erreure lors de la compilation.
      ServerSocket serveur = new ServerSocket (1200); // erreure ici
      Socket serviceSocket = serveur.accept();
      0
    4. KX Messages postés 19031 Statut Modérateur 3 020
       
      @vanrostand : ne te greffe pas sur une discussion qui a plus de 3 ans !
      Regarde ici pour bien commencer, si ça ne résout pas ton problème créé une nouvelle discussion.
      0
  2. DjSKeud Messages postés 103 Statut Membre 31
     
    bonjour,

    arrives-tu déja à communiquer entre client et serveur (juste un "hello world") ?
    J'ai fais un truc de ce genre en cours l'an dernier, je vais essayer de te le retrouver dnas les prochains jours.

    Ps: j'ai eu le meme probleme que toi il y a quelques années en C, qui venait en fait du type d'ouverture du fichier (open ou fopen)

    ++
    1
  3. DjSKeud Messages postés 103 Statut Membre 31
     
    oui voila, c'est ce que j'ai du faire en C. En fait j'avai créé une struct avec ma trame de donnees (taille fixe) et un int définissant la taille. On peut se dire que l'int ne sert pas, mais en fait on en a besoin pour la derniere trame, pke sinon tu va la prendre pour une trame de égalment 4096bytes, alors qu'elle peut etre plus courte (tous les fichiers n'ont pas une taille d'un multiple de 4096 :) )

    Suis-je assez clair dans mon raisonement ?
    1
  4. Valryon
     
    Oui oui j'arrives à échanger des messages ainsi que des objets.

    Je pense avoir trouver la solution :
    Du côté client, il faut découper le fichier à envoyer en morceaux de 4096 octets et envoyer sur la socket au fur et à mesure.

    Le serveur quant à lui s'occupe de recevoir 4096 bytes par 4096 bytes, et les envoie dans le fichier.

    Une fois le transfert terminé (je ne sais pas trop comment déterminer cela) le serveur ferme le fichier et les flux ouverts.

    La technique d'envoi binaire sans découpage marche, mais sur des fichiers de moins de 10Mo. En effet après le système essaye de mettre plus de 10 millions de bytes dans un tableau ce qui a vite fait de saturer la mémoire :)
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Valryon
     
    Oui oui tout a fait, la dernière trame doit être traitée différement, c'est un miracle si elle fait la même taille que les autres ! :p

    Bon maintenant j'ai un autre problème que je vais tâcher de résoudre, le transfert est bien effectué mais le fichier que j'obtiens est minimum 5fois plus gros. On dirait qu'il ajoute a chaque fois le tampon dans le fichier, sauf que ce tampon n'est pas vidé. Du coup j'ai quelque chose comme :
    1
    1
    2
    1
    2
    3
    1
    2
    3
    4

    au lieu d'un fichier
    1
    2
    3
    4
    5

    Il faut que j'arrive à vider ce BufferInputStream donc.
    0
  7. DjSKeud Messages postés 103 Statut Membre 31
     
    Oui il à l'air de faire un truc du genre BufferInputStream = BufferInputStream + New_BufferInputStream (je me comprend :) )
    Si j'ai une piste, je n'hésiterai pas à te le faire savoir..

    0
  8. Valryon
     
    Pour le reset c'était :
    tableaubytes.reset();

    Comme ça le tableau est remis à 0.
    0
  9. williamsko
     
    Salut,
    Moi je l'ai fait en JAVA.
    Pour récupérer le chemin absolu du fichier à envoyer j'ai utilisé un JFileChooser.
    Ensuite j'ai envoyer ce nom de fichier au serveur(par exemple).
    Le serveur de son coté crée directement un fichier du mm nom que le fichier qui a été envoyé.
    Du coté du client j'ai organisé une boucle while qui permet de compter le nombre de lignes dans le fichier.
    Ce nombre est ensuite envoyé au serveur qui de son coté organise une boucle forpour récupérer chaque lligne qui lui sera envoyé.
    C'est simple comme algo.Je dirai pas trop pro.
    Mais c mon niveau.Je me suis débrouillé seulement.
    0
    1. bm_marco
       
      je me demandais si tu pouvais me faire part de ce bout d'algo si possible stp, car g comme projet de faire une sorte de messenger en java, pas de probleme avec les clients pour communiquer entre eux, mais g du mal a transferer des fichiers d'un client a un autre.
      0
    2. sfpirate
       
      slt williamsko

      je suis en train de faire un programme en java qui doit faire le transfert d'un fichier d'un serveur à un client
      j'ai moi aussi utiliser la commande JFilechooser mon probleme et ke je ne sais pas comment l'implementer dans ma socket client serveur.
      et puis pour faire le transfert d'un fichier alors la c une autre paire de manche je ne c meme pas kel commande utiliser faut dire ke je suis debutant en java

      et g trouvé un post it de toi parlant de ca
      si tu pouvais m'aider ca serais vraiment sympas

      voici mon mail sfpirate16@hotmail.com

      merci davance
      0