[JAVA] Transfert de fichier par sockets

[Résolu/Fermé]
Signaler
-
Messages postés
16383
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2021
-
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

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();

}
22
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 65492 internautes nous ont dit merci ce mois-ci

Messages postés
97
Date d'inscription
mardi 25 avril 2006
Statut
Membre
Dernière intervention
22 avril 2015
32
...cool, c'est "tampon.flush();" qui à solutionné ton problème ?
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
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();
Messages postés
16383
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2021
2 866
@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.
Messages postés
97
Date d'inscription
mardi 25 avril 2006
Statut
Membre
Dernière intervention
22 avril 2015
32
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)

++
Messages postés
97
Date d'inscription
mardi 25 avril 2006
Statut
Membre
Dernière intervention
22 avril 2015
32
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 ?
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 :)
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.
Messages postés
97
Date d'inscription
mardi 25 avril 2006
Statut
Membre
Dernière intervention
22 avril 2015
32
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..

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

Comme ça le tableau est remis à 0.
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.
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.
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