2012-02-27 2 views
3

J'ai un problème avec les données de lecture NetworkStream du tampon de socket qui ne devraient pas s'y trouver. J'envoie d'énormes tampons au passage. En ce moment je viens de tester sur le localhost.NetworkStream lit les données qui ne devraient pas s'y trouver

Voici comment je lis les données, les 4 premiers octets contiennent la longueur du message, puis je viens de lire en 4096 morceaux jusqu'à ce qu'il atteigne la longueur du message.

protected TcpClient tcpObject; 
    protected NetworkStream tcpStream; 

    private void HandleComm() 
    { 
     try 
     { 
      tcpStream = tcpObject.GetStream(); 
      byte[] totalByteAray = new byte[constIntSize]; 
      byte[] message = new byte[constChunkSize]; 
      byte[] fullMessage = new byte[0]; 

      //this is how many bytes long the message will be 
      int totalBytes = 0; 
      int currentBytes = 0; 
      int chunkSize = constChunkSize; 

      while (true) 
      { 
       //skip reading if no data is available 
       //DataAvailable does not tell you when all the data has arrived 
       //it just tell you if some data has arrived 
       if (tcpStream.CanRead) 
       { 
        totalBytes = 0; 
        currentBytes = 0; 
        message = new byte[constChunkSize]; 
        chunkSize = constChunkSize; 

        //The first 4 bytes of the message will always contain the length of the message, not including 
        //the first 4 bytes. This is how you know when to stop reading. 
        tcpStream.Read(totalByteAray, 0, constIntSize);       
        //there are 4 bytes in a 32 bit number, so totalByteArrayContains 4 index that is a byte which is 
        //the 32 bit int that tells us how many bytes the whole message will be. 
        //now convert the totalByteArray to a 32bit int 
        totalBytes = BitConverter.ToInt32(totalByteAray, 0); 
        Console.WriteLine("reading " + totalBytes); 
        //fullMessage will contain the entire message but it has to be built message by message.      
        fullMessage = new byte[totalBytes]; 
        //keep reading until we get all the data 
        while (currentBytes < totalBytes) 
        { 

         //when you send something over TCP it will some times get split up 
         //this is why you only read in chuncks, 4096 is a safe amount of bytes 
         //to split the data into. 
         if (totalBytes - currentBytes < constChunkSize) 
         { 
          chunkSize = totalBytes - currentBytes; 
          message = new byte[chunkSize]; 
         } 

         tcpStream.Read(message, 0, chunkSize); 
         //since we know each chunk will always come in at 4096 bytes if it doesn't that means that it's the end 
         //this part cuts off the extra empty bytes       

         //copy the message to fullMessage starting at current bytes and ending with the bytes left 
         message.CopyTo(fullMessage, currentBytes); 
         currentBytes += chunkSize;        
        } 

        //message has successfully been received 
        if (totalBytes != 0) 
        { 

         if (OnRawDataReceived != null) 
         { 
          RawDataReceivedArgs args = new RawDataReceivedArgs(); 
          args.Data = new byte[fullMessage.Length]; 
          fullMessage.CopyTo(args.Data, 0); 
          OnRawDataReceived(this, args); 
         } 

         totalBytes = 0; 
        } 
       } 
      } 
     } 
     catch 
     { 
      connectionStatus = ConnectionStatus.NotConnected; 
      if (OnDisConnect != null) 
       OnDisConnect(this, null); 
     } 
    } 

Voici comment j'envoie les données, je viens d'obtenir la longueur du message, puis créer un nouveau message avec les 4 premiers octets étant la longueur du message et le reste étant le message réel.

protected void sendData(byte[] data) 
    { 
     //we need to know how big the data that we are sending will be 
     int length = data.Length; 
     System.Console.WriteLine("writing " + length); 
     //convert the 32bit int to a 4 byte array 
     byte[] lengthArray = BitConverter.GetBytes(length); 

     //init the main byte array that will be sent over 
     byte[] buffer = new byte[length + constIntSize]; 

     //the first 4 bytes will contain the length of the data 
     lengthArray.CopyTo(buffer, 0); 

     //the rest of the buffer will contain the data being sent 
     data.CopyTo(buffer, constIntSize); 

     //wite it to the client stream 
     tcpStream.Write(buffer, 0, length + constIntSize); 
     //now send it 
     tcpStream.Flush();   
    } 

Pour une raison quelconque, je reçois des données de lecture qui ne doivent pas figurer dans le tampon. Voici la sortie de la console.

serveur

------------- client

écriture 1024 -> Lecture 1024

lecture 1.228.800 < - écriture 1228800

écriture 1024 -> 1024 lecture

lecture 1.228.800 < - écriture 1228800

lecture 7.224.842

Donc, quand je clique sur un bouton, il envoie une requête disant que je veux une image d'une caméra Web, la demande est de 1024 octets. Le client le lit et envoie l'image qui est le 1228800 octets. La première fois que je fais cela, ça fonctionne toujours. La deuxième fois que je l'ai cliqué, le client a renvoyé les 1228800 octets, le serveur a lu le bon nombre d'octets et a trouvé plus d'octets à lire lorsque le tampon de socket aurait dû être vide. Je n'avais pas 7224842 octets dans le tampon socket, c'est exactement ce que disent les 4 premiers octets de la lecture.

Des idées sur les raisons pour lesquelles le tampon reçoit des données supplémentaires? Tout semble bien fonctionner quand j'envoie des messages plus petits, mais cela me rend fou.

+3

La méthode Read retourne NetworkStream 'Le nombre d'octets lus à partir du NetworkStream.'. Vous ignorez la valeur de retour. Vous ne pouvez pas supposer que la valeur va être la taille du tampon. –

Répondre

6
tcpStream.Read(totalByteAray, 0, constIntSize); 
... 
tcpStream.Read(message, 0, chunkSize); 

et là nous avons tout le problème. C'est une exigence que vous vérifiez le retour à cela. Il n'est pas garanti (et pour les E/S basées sur le réseau, assez improbable) que vous obteniez tout le tampon en une fois - les paquets arrivent au fur et à mesure, et l'API vous donnera ce qu'il peut. Au contraire, vous obtiendrez "quelques" (résultat> 0 et < = compte) ou "aucun" (résultat < = 0).

Si vous voulez lire exactement que beaucoup de données, puis écrire une méthode utilitaire:

static void ReadExact(Stream stream, byte[] buffer, int offset, int count) 
{ 
    int read; 
    while(count > 0 && (read = stream.Read(buffer, offset, count)) > 0) { 
     offset += read; 
     count -= read; 
    } 
    if(count != 0) throw new EndOfStreamException(); 
} 
+0

Merci beaucoup Marc, ça a fonctionné parfaitement. J'ai passé des heures à déboguer et je n'ai pas trouvé d'endroit. Après avoir lu votre message, je l'ai réparé en 2 minutes. – Rickyman35

Questions connexes