Transfert de fichier

Description

Ce petit programme permet simplement de transférer un fichier entre deux machines.

Côté client; le programme lit un fichier par paquets (par défaut, les paquets sont de 32768 bits)
Le tableau de bytes est serializé (avec un BinaryFormatter) et envoyé dans la foulée via un objet NetworkStream.

Côté serveur; on déserialize le tableau de bytes venant du NetworkStream et on écrit le fichier au fur et à mesure des paquets reçus.

Petit bonus : Avant l'envoi du fichier, le client envoi un objet FileTransfer pour indiquer au serveur le nom et la taille (en octets) du fichier

Dans le zip, il y aussi une vérification de l'intégrité du fichier avec un hash sha1

Pour l'utiliser, lancer l'exécutable sur deux machines;
- Sur l'un utilisez le mode serveur, sur le second le mode client
- le client doit indiquer l'ip du serveur
- l'utilisateur du client indique le nom du fichier
- le fichier est transféré

Source / Exemple :


using System;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;

namespace FileTransfer
{
    class Program
    {
        static void Main()
        {

            Console.Write("Mode client ou serveur ? (C/S) : ");
            string mode = Console.ReadLine().ToUpper();

            Int64 buffersize = 32768;
            DateTime dt_debut;

            if (mode == "C")
            {
                //Connexion
                Console.Write("ip serv : ");

                TcpClient tc = new TcpClient();
                tc.Connect(new IPEndPoint(IPAddress.Parse(Console.ReadLine()), 1337));
                NetworkStream ns = tc.GetStream();

                Console.WriteLine("serveur connecté");
                Console.Write("filename : ");
                String filename = Console.ReadLine();

                
                //Send File infos
                BinaryFormatter bf = new BinaryFormatter();

                String filehash = FileHash(filename);
                Int64 filesize = new FileInfo(filename).Length;
                FileTransfer ft = new FileTransfer(filename, filesize, filehash);

                bf.Serialize(ns, ft);
                dt_debut = DateTime.Now;

                //ok, read/send the file
                FileStream fs = new FileStream(filename, FileMode.Open);
                Int64 bytesOk = 0;

                while (bytesOk < filesize)
                {
                    if (filesize - bytesOk < buffersize)
                        buffersize = filesize - bytesOk;

                    Byte[] buffer = new Byte[buffersize];
                    fs.Read(buffer, 0, (int)buffersize);
                    bf.Serialize(ns, buffer);

                    bytesOk += buffersize;

                    Console.Write("\rSent : " + Math.Round((double)bytesOk / filesize * 100) + "%");
                }

                Console.WriteLine("\r\nfichier envoyé");

                ft = (FileTransfer)bf.Deserialize(ns);
                Console.WriteLine((ft.hash == filehash) ? "fichier bien recu" : "erreur lors du transfert");

                //Close ALL the object\r\n
                fs.Close();
                ns.Close();
                tc.Close();
            }
            else
            {
                Console.WriteLine("En attente du client");

                //Attente d'un client
                TcpListener tl = new TcpListener(new IPEndPoint(IPAddress.Any, 1337));
                tl.Start();
                TcpClient tc = tl.AcceptTcpClient();
                tl.Stop();
                NetworkStream ns = tc.GetStream();

                Console.WriteLine("Client connecté");
                

                //Receive File infos
                BinaryFormatter bf = new BinaryFormatter();
                FileTransfer ft = (FileTransfer)bf.Deserialize(ns);

                Console.WriteLine(ft.name + " - " + ft.size);
                Int64 filesize = ft.size;
                String filename = ft.name;
                String filehash = ft.hash;
                dt_debut = DateTime.Now;

                //ok, receive/write the file
                FileStream fs = new FileStream(filename, FileMode.Create);
                Int64 bytesOk = 0;

                while (bytesOk < filesize)
                {
                    Byte[] buffer = (Byte[])bf.Deserialize(ns);
                    buffersize = buffer.Length;
                    fs.Write(buffer, 0, (int)buffersize);
                    bytesOk += buffersize;

                    Console.Write("\rReceived : " + Math.Round((double)bytesOk / filesize * 100) + "%");
                }

                Console.WriteLine("\r\nfichier écrit");
                Console.WriteLine((ft.hash == filehash) ? "fichier bien recu" : "erreur lors du transfert");

                bf.Serialize(ns, new FileTransfer("", 0, filehash));

                //Close ALL the object\r\n
                fs.Close();
                ns.Close();
                tc.Close();
            }

            TimeSpan ts = DateTime.Now - dt_debut;
            Console.WriteLine("Temps total : " + (ts.Minutes + "m " + ts.Seconds + "s " + ts.Milliseconds + "ms"));

            Console.Read();
        }

        static String FileHash(String filename)
        {
            SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
            byte[] buffer;

            using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read))
                buffer = sha1.ComputeHash(fs);

            return BitConverter.ToString(buffer).Replace("-", String.Empty);
        }
    }

    [Serializable]
    public class FileTransfer
    {
        public String name;
        public Int64 size;
        public String hash;

        public FileTransfer(String name, Int64 size, String hash)
        {
            this.name = name;
            this.size = size;
            this.hash = hash;
        }
    }
}

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.