Problème de transfert : données remplacer par les Spaces !

Signaler
Messages postés
100
Date d'inscription
mercredi 27 avril 2011
Statut
Membre
Dernière intervention
21 décembre 2012
-
Bonjour !

J'ai dû réaliser pour une application du transfert de fichier entre 2 PC.
J'ai mis en place une communication en TCP/IP, avec les "outils" TCPClient et TCPListener.

J'ai fait fonctionner le tout dans mon entreprise, tout marche parfaitement (on l'utilise dans un atelier) !
Mes collègues sont allés chez le client pour l'installer, ils ont vite vu apparaître un problème lors des transferts : certains paquets de données sont remplacés par une séries d'espace (j'envoie mes données par 4096 octets, c'est peut-être un peu fat ?), et de temps à autre, on retrouve les données perdues plus loin dans le fichier !!!
A savoir, les données en elles-même ne sont alors pas altérées (c'est du fichier texte), le tout reste lisible...
A noter aussi que dans la configuration où le transfert plante, le câble éthernet passe le long de câbles d'alim de machine en 420V, avec de fortes puissances. Je suis en train de me pencher sur du CheckSum pour palier à ces problèmes, mais j'ai un doute : si c'était juste des interférences, j'aurais juste des valeurs modifier de manière plutôt aléatoire, et non pas des paquets de donnés entier qui sont remplacer par des espaces non ? A moins que les TCPClient et Listener n'ai des genres de protection qui empêche des paquets corrompus de passer ?

Quelqu'un a une explication ?

Je vous met un bout de code pour vous présenter rapidement ma communication :

Serveur :
string fichierPath = @"Fichiers\Temp.txt";
byte[] dataIN = new byte[4096];      //Paquets de données réceptionnés
byte[] dataEndFile;
int iBcl = 0;
int iCptBuffers;
string stTrameInit;
long iTailleFichier = 0;
string stNomFichier = "";
int iNbOctRestant = 0;

FileStream Fichier = null;               //Pour réécrire le fichier après réception
BinaryWriter EcrivainFichier = null;


if (LeClient.GetStream().Read(dataIN, 0, dataIN.Length) != 0)
{
    stTrameInit = Encoding.UTF8.GetString(dataIN);                               //On récupère la trame en string

    DecodeTrameInit(stTrameInit, ref iTailleFichier, ref stNomFichier);          //On décode la trame (on récupère la taille et le nom du fichier)

    LeClient.GetStream().Write(Encoding.UTF8.GetBytes("Acknowledge"), 0, 11);       //On envoie l'Acq


    //On prépare l'écriture du fichier reçu
    Fichier = new FileStream(fichierPath, FileMode.Create, FileAccess.ReadWrite);   //On instancie le FileStream et le BinaryWriter, pour
                                                                                    //écrire dans le fichier
    EcrivainFichier = new BinaryWriter(Fichier, Encoding.UTF8);

    iCptBuffers = 0;

    LeClient.GetStream().Read(dataIN, 0, dataIN.Length);          //On réceptionne les premières données du fichier. On gère les erreurs
                                     //éventuelles grâce au timeout et au try/catch, au cas où le serveur ou le client s'arrête brutalement.

    while (EcrivainFichier.BaseStream.Position + dataIN.Length <= iTailleFichier)     //On continue à réceptionner tant qu'il reste plus d'un
                                                                                      //buffer (4096 octets) à transmettre
    {
        EcrivainFichier.Write(dataIN, 0, dataIN.Length);                              //On écrit les données réceptionnées dans le fichier
        LeClient.GetStream().Write(Encoding.UTF8.GetBytes(Convert.ToString(iCptBuffers)), 0, Convert.ToString(iCptBuffers).Length);
                   //On envoie comme acquittement la position actuelle d'écriture (nombre de buffers déjà reçu)

        LeClient.GetStream().Read(dataIN, 0, dataIN.Length);                                      //On attend les données suivantes

        iCptBuffers++;
    }

    //On sort de la boucle quand il reste moins d'1 buffer. On récupère donc le nombre d'octet restant
    iNbOctRestant = (int)(iTailleFichier - EcrivainFichier.BaseStream.Position);

    dataEndFile = new byte[iNbOctRestant];                //On instancie un tableau d'octet de la taille correspondante

    for (iBcl = 0; iBcl < iNbOctRestant; iBcl++)          //On récupère les valeur reçues en dernier octet par octet dans le nouveau tableau
    {
        dataEndFile[iBcl] = dataIN[iBcl];
    }

    EcrivainFichier.Write(dataEndFile, 0, dataEndFile.Length); //On écrit dans le fichier ce dernier tableau de valeur, achevant la réception.

    LeClient.GetStream().Write(Encoding.UTF8.GetBytes(Convert.ToString(iCptBuffers)), 0, Convert.ToString(iCptBuffers).Length);
         //On envoie le dernier acquittement


    EcrivainFichier.Close();
    Fichier.Close();                //On ferme le flux du fichier



Client :
TcpClient monClient = null;
FileStream EnvoiFichier = null;
FileInfo InfoFichier = null;
BinaryReader LecteurFichier = null;


byte[] dataOUT = new byte[4096];      //Permet de stocker les données à transmettre (buffer)
byte[] dataAck = new byte[12];        //Buffer pour l'acquittement (plus petit, pour transmettre le pacquet plus vite)
int iAcquittement = 0;                //Stocke la position actuelle du fichier (nombre de buffer déjà transmis), dpnnée par le serveur
int iCptBuffers = 0;                  //Stocke la position actuelle du fichier (nombre de buffer déjà transmis)
//=> On effectue une comparaison entre les 2 pour vérifier la cohérences des données transmises
int iNbOctet = 9999;                  //Pour vérifier la lecture du fichier, et pour les erreurs de transfert


iCptBuffers = 0;
do
{
iNbOctet = 9999;

iNbOctet = LecteurFichier.Read(dataOUT, 0, dataOUT.Length);         //On lit les données du fichier, en spécifiant la position et le nombre
                                                                    //d'octet à lire. On essaie de lire chaque fois 4096 valeurs (buffer).
    //Note : Après chaque lecture, la position de lecture s'incrémente d'autant d'octet lus (dans le fileStream) ! On spécifie donc 0 pour la
    //position (pas d' "offset" )
    //On récupère le nombre d'octet lu (afin de vérifier si l'on a bien lu un buffer complet : 4096 octets


if (iNbOctet != 9999)        //Si on a lu correctement dans le fichier. Le nombre d'octet doit normalement aller de 0 à 4096.
{
    monClient.GetStream().Write(dataOUT, 0, iNbOctet);  //On écrit dans le flux du client le tableau d'octet contenant les données de la ligne
                                
    if (monClient.GetStream().Read(dataAck, 0, dataAck.Length) != 0)        //Si on a bien receptionné la réponse du serveur (Acknowledge)
    {
        iAcquittement = Convert.ToInt32(Encoding.UTF8.GetString(dataAck, 0, Convert.ToString(iCptBuffers).Length));
               //On récupère la valeur de l'acquittement renvoyé par le serveur

        if (iAcquittement != iCptBuffers)               //Si l'acquittement reçu diffère de la position courante du client, il y a erreur
        {
            stReturnError = "Erreur lors du transfert : Erreur lors de la réception des données courantes";
            iNbOctet = 9999;        //Pour sortir de la boucle, car erreur
        }
        else
        {
            iCptBuffers++;      //Sinon on incrémente le compteur en prévision de la prochaine ligne
        }
    }
    else
    {
        iNbOctet = 9999;        //Pour sortir de la boucle, car erreur
        stReturnError = "Erreur lors du transfert : réponse du serveur incohérente";
    }
}
else
{
    iNbOctet = 9999;        //Pour sortir de la boucle, car erreur
    stReturnError = "Erreur lors de la lecture du fichier";
}

} while (iNbOctet == dataOUT.Length);       //On continue tant que le nombre d'octets lus correspond bien à la taille du buffer
        //(cela signifie qu'il reste plus d'un buffer de 4096 octets à lire, ou qu'il reste strictement 0 octet à lire, auquel cas
        //la boucle suivante sera la dernière et rien ne sera envoyé, comme il ne reste rien à lire !)