Bewise

Nous développons... votre avance

BewisePeerToPeer - Une classe de transfert de fichiers

SLF
06/01/2006 - Sébastien Pertus
Télécharger la version Word
Télécharger les sources

1 Présentation

Cet article vous propose aujourd’hui de créer une nouvelle classe de transfert de fichiers sur un réseau Tcp, à l’aide des classes présentes dans le Framework 2.0.

Pour illustrer notre exemple, vous trouverez deux applications consoles simplistes, en plus de notre assembly, permettant de tester celle-ci afin de télécharger un simple fichier.

Le pré-requis nécessaire est d’avoir déjà manipulé les technologies liées à la plateforme .NET.

Une connaissance des délégués est nécessaire pour appréhender les appels de procédures asynchrones.

Aucune connaissance particulière sur le Framework .NET 2.0 n’est obligatoire, puisque nous détaillerons chacune d’elles au cours de cet article.

Quelques notions de transfert réseaux faciliteront votre compréhension de l’ensemble.

Notre assembly BewisePeerToPeer sera composée de deux classes :

  • BewisePeerToPeer.Server
  • BewisePeerToPeer.Client

Cet article a été réalisé sur les versions suivantes :

§ Framework .NET version 2.0.50727

§ Visual Studio 2005 version 8.0.50727.42 (RTM.050727-4200)

2 BewisePeerToPeer.Server

Notre Classe Serveur assurera deux rôles principaux :

· Assurer l’autorisation d’un client à se connecter, lorsque celui-ci en fera la demande. Nous partirons du principe dans notre exemple que le client est toujours autorisé.

· Envoyer via un flux réseau, en l’occurrence, le fichier demandé par notre client.

Le principal objet utilisé dans cette assembly est la classe TcpListener.

TcpListener fournit des méthodes simples qui écoutent et acceptent (ou refusent) des connexions entrantes sur un port et une adresse Tcp donnée.

TcpListener peut travailler en mode asynchrone, et nous utiliserons bien entendu cette méthode, plus souple à l’utilisation.

2.1 TcpListener

Avant d’aborder les flux réseaux, nous allons voir comment gérer le modèle asynchrone de notre TcpListener.

J’ai pris le soin au préalable de protéger mon listener en créant une propriété, comme suit :

// Listener de type Tcp private TcpListener listenerTcp; /// <summary> /// Accesseur du Listener de type Tcp /// </summary> public TcpListener ListenerTcp { get{return listenerTcp;} set{listenerTcp = value;} }

Une fois notre listener démarré [méthode Start()] il est nécessaire de récupérer les flux clients.

Ceci est réalisé grâce à la méthode AcceptTcpClient().

Bien entendu, il existe la version asynchrone de cette méthode qui n’est autre que .BeginAcceptTcpClient()


2.1.1 Initialisation
public void Start(Int32 port, String iPAddress) { try { IPAddress localAddr = IPAddress.Parse(iPAddress); ListenerTcp = new TcpListener(localAddr, port); // Début d'écoute des requetes clients. ListenerTcp.Start(); this.StartListenToTcpClient(); } catch (SocketException e) { throw e; } }

2.1.2 Lancement asynchrone

/// <summary> /// Débute l'écoute d'une connexion Tcp Client /// </summary> public void StartListenToTcpClient() { // Pointeur asynchrone IAsyncResult iar = null; //Attente du prochain message iar = ListenerTcp.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientCallback), this); } /// <summary> /// Asynchrone d'accepation de connexion /// A la fin de la récupération, je relance une autre écoute /// </summary> public void AcceptTcpClientCallback(IAsyncResult ar) { try { … } }


2.1.3 Réception du flux client

Maintenant que notre Listener est capable de récupérer un flux client, il est nécessaire de traiter la demande et de renvoyer une réponse (un flux en guise de réponse).

Le transfert de flux s’effectue via l’objet NetworkStream.

La classe NetworkStream fournit des méthodes de transfert (réception et envoi) de données au travers d’un flux réseau.

Dans notre exemple, nous allons récupérer le flux client, qui en entête, nous donnera l’ordre à exécuter.

Les ordres client seront simples :

· Demande d’autorisation de connexion

· Demande de transfert d’un fichier

En réponse, et via notre classe NetworkStream, nous enverrons le flux de retour.

Mais, tout d’abord, la réception du flux client :

// Récupération du flux du poste client NetworkStream stream = client.GetStream(); // Lecture du flux entrant Int32 i = stream.Read(bytes, 0, bytes.Length); // Décodage data = System.Text.Encoding.UTF8.GetString(bytes, 0, i); // Découpage tabArgs = data.Split(new char[] { '|' }); // Analyse de l'ordre à éxécuter // demande d'authentification if (data.StartsWith("Request", StringComparison.CurrentCultureIgnoreCase)) { this.CheckForAutorisations(tabArgs, stream, server); } else { this.SendFile(tabArgs, stream, server); } // Fermeture de la connexion courante client.Close();


2.1.4 Envoi du flux de réponse

Une fois notre flux reçu et la demande analysée (autorisation ou demande de téléchargement), il ne reste plus qu’à utiliser notre flux réseau déjà ouvert par le client, pour renvoyer notre réponse.

Je vous laisse regarder les sources de l’article pour avoir un aperçu de la réponse, lors de l’authentification ; nous allons ici détailler le processus d’envoi du fichier.

Le principe reste relativement simple : une fois récupérés les arguments de l’entête du flux client (qui contient le fichier à télécharger), il suffit d’ouvrir un flux fichier en lecture, avec l’objet FileStream, et de le lire à l’aide d’un BinaryReader.

J’utilise la méthode .Read() de mon Reader binaire pour remplir un tableau de Byte, que j’envois en retour sur mon flux NetworkStream.

//Nom du fichier à récupérer FilePath = tabArgs[1]; // Vérification de l'existence du fichier if (!System.IO.File.Exists(FilePath)) { throw new System.IO.FileNotFoundException("Bewise Peer to Peer : Fichier non trouvé sur le serveur", FilePath); } // Récupération des informations relatives au fichier System.IO.FileInfo fileInfo = new System.IO.FileInfo(FilePath); // Ouverture d'un flux vers le fichier souhaité. fs = new FileStream(fileInfo.FullName, FileMode.Open); // Création d'un Reader Binaire sur ce flux br = new BinaryReader(fs, Encoding.UTF8); //Transformation en tableau de Byte Byte[] bb = new Byte[1024]; while (br.Read(bb, 0, bb.Length) != 0) { // Envoi du fichier en retour networkStream.Write(bb, 0, bb.Length); }


3 BewisePeerToPeer.Client

Notre Classe Client assumera deux rôles principaux :

· Demander l’autorisation de connexion au serveur.

· Envoyer le nom du fichier à télécharger et le récupérer.

Ici nous utiliserons principalement la classe TcpClient, qui permet de se connecter à un server, pour peu que celui-ci soit démarré.

Il suffit alors de faire une demande et d’accepter en retour le flux renvoyé par le serveur.

Il faut bien sûr écrire ce flux sur un espace disque accessible, et dont vous disposez des droits d’accés.

3.1 TcpClient

Une fois connecté au serveur, le TcpClient nous renvoie, via la méthode GetStream(), le flux en cours sur le port et à l’adresse spécifiée.

Pour ne pas occuper le thread principal, nous ferons appel à un délégué asynchrone pour gérer le transfert du fichier, qui peut être volumineux, et ce afin d’éviter notamment les phénomènes tel que le « blocage » de la fenêtre d’exécution.

3.2 Autorisation

Elle se fait par un simple envoi de données texte au format binaire. Nous aurions pu bien sur utiliser d’autre format de demande comme le remoting par exemple.

Suivant la réponse du serveur, notre client est considéré comme « connecté », ou non.

// Creation d'un TcpClient TcpClient client = new TcpClient(iPAddress, port); // Ouvrir le flux NetworkStream networkStream = client.GetStream(); // Construction d'un message de demande de connexion string request = string.Format("Request|{0}", Client.GetHostAddress()); // Récupération du tableau de Byte correspondant Byte[] requestByte = Encoding.UTF8.GetBytes(request); // Ecriture dans le flux réseau networkStream.Write(requestByte, 0, requestByte.Length); // --------Réponse du serveur------------------------------- // Récupération du flux de retour. Byte[] bytes = new Byte[256]; Int32 i = networkStream.Read(bytes, 0, bytes.Length); // Décodage String data = System.Text.Encoding.UTF8.GetString(bytes, 0, i); String[] tabArgs = data.Split(new char[] { '|' }); isConnected = Convert.ToBoolean(tabArgs[1]);

3.3 Réception

Tout d’abord, il nous faut créer un délégué asynchrone pour démarrer le téléchargement.

Le sujet de l’article n’étant pas accès sur ce type de délégué, voici succinctement un aperçu du code :

3.3.1 Délégué asynchrone
public delegate void AsynchroneDownloadDelegate(BinaryWriter w, FileStream fs, NetworkStream ns); private AsynchroneDownloadDelegate threadStart; /// Download d'un fichier /// </summary> public void DownloadFile(string serverFullFilePath, string localFullFilePath) { try { … // Démarrage dun processus asynchrone threadStart = new AsynchroneDownloadDelegate(AsynchroneBeginDownload); AsyncCallback asyncCallback = new AsyncCallback(AsynchroneEndDownload); threadStart.BeginInvoke(w, fs, networkStream, asyncCallback, threadStart); } } /// <summary> /// Asynchrone /// </summary> private void AsynchroneBeginDownload(BinaryWriter w, FileStream fs, NetworkStream ns) { … } /// <summary> /// Fin du Download /// </summary> private void AsynchroneEndDownload(IAsyncResult ar) { AsynchroneDownloadDelegate threadStart = (AsynchroneDownloadDelegate)ar.AsyncState; threadStart.EndInvoke(ar); }

3.3.2 Téléchargement du fichier

Le téléchargement du fichier se fait tout simplement, une requète de demande avec le nom du fichier en entrée, et la réception du fichier comme réponse.

Il suffit alors d’ouvrir un flux fichier (en mode écriture !) et réceptionner le flux réseau donné par notre TcpClient

// Creation d'un TcpClient TcpClient client = new TcpClient(this.ipAddress, this.port); // Ouvrir le flux NetworkStream networkStream = client.GetStream(); // Construction d'un message de demande de téléchargement string request = string.Format("Download|{0}", serverFullFilePath.ToString()); Byte[] b = Encoding.UTF8.GetBytes(request); // Envoi du message networkStream.Write(b, 0, b.Length); // ----Réponse--------------------------------------------------------- // Ouverture d'un flux vers un fichier client. FileStream fs = new FileStream(localFullFilePath, FileMode.OpenOrCreate); // Création d'un Writer Binaire sur ce flux BinaryWriter w = new BinaryWriter(fs); // Démarrage dun processus asynchrone threadStart = new AsynchroneDownloadDelegate(AsynchroneBeginDownload); AsyncCallback asyncCallback = new AsyncCallback(AsynchroneEndDownload); threadStart.BeginInvoke(w, fs, networkStream, asyncCallback, threadStart);

4 Conclusion

Nous venons de créer facilement, une simple assembly de transfert de fichier, grâce aux outils et fonctionnalités fournies par le Framework .net 2.0

Vous trouverez le code complet et fonctionnel de ce petit outil dans les sources de l’article.

Cet article a pour vocation d’appréhender un coté qui peut être considéré quelque fois comme obscur, les transferts réseaux, mais qui s’avère au final très simple, grâce notamment à la puissance des outils et du langage .NET.

Il vous deviendra alors aisé de développer vos propres outils de transferts.

> Tous les articles

Commentaires

aucun commentaire
Page 1/1
   
Connexion
  • Accueil
  • Plan du site
  • Contact
Bewise TV, Blog technique, Webcasts...

Votre carrière et nous

  • Nos offres
  • Votre candidature
Ignorer les liens de navigation > Accueil > Nos Métiers > Solutions Langages et Framework > Détail Article
Ignorer les liens de navigation
Nous
Nos Métiers
Vous Former
Nos Evénements
Nos Références
Nos Activités
Nos Certifications
Nos Chiffres
Le Groupe
Nos Partenaires
On Parle de Nous
Votre Carrière et Nous
Nous Contacter
Défiler vers le haut
Défiler vers le bas
Administration, Système et Communication
Architecture, Méthodes, Industrialisation
Décisionnel et Gestion des Données
Nouvelles Interfaces Utilisateurs
Portail et Travail Collaboratif
Solutions Langages et Framework
Solutions Web Avancées
Défiler vers le haut
Défiler vers le bas
Nos cours
Le Planning
Offres promotionnelles
Défiler vers le haut
Défiler vers le bas
TechDays'12
TechLunch
Windows 8 Camp
Défiler vers le haut
Défiler vers le bas
  • Infos légales
  • Lettre du Regional Director
  • Revue de presse