2014-04-30 1 views
1

J'écris une application cliente (service windows) qui lit régulièrement des données et écrit des données sur un serveur. Le serveur est configuré pour toujours répondre au client si le cadre qu'il a reçu est compris. J'ai la méthode suivante pour l'envoi et la réception:Quand fermer tcpclient et networkstream

public byte[] Sendmessage(byte[] arrbMessage) 
    { 
     byte[] arrbDataInput;            // byteArray for received data 

     try 
     { 
      _oStream = _oClient.GetStream();        // try to get a networkstream 
     } 
     catch (InvalidOperationException e) 
     { 
      Connect();              // if this fails, tcpclient is probably disconnected, reconnect client and networstream 
     } 

     if (_oClient.Connected) 
      try 
      {                // Send the arrbMessage to the connected TcpServer. 
       string sKey = "123456789ABC"; 
       byte[] arrbMessageEncrypted = EncryptedFrame(arrbMessage, sKey);     

       if (_oStream.CanWrite)          // if stream is available for writing 
       { 
        _oStream.Write(arrbMessageEncrypted, 0, arrbMessageEncrypted.Length);  //send message 
        _oStream.Flush();          //Clear stream 
       } 
       // Receive the TcpServer.response. 
       if (_oStream.CanRead)          // if stream is available for reading 
       { 
        arrbDataInput = new byte[256];       // set inputbuffer to 256 
        //_oClient.NoDelay = true;        // don't wait if nothing is received 
        // Read the first batch of the TcpServer response bytes. 
        _oStream.ReadTimeout = 2000; 
        Int32 bytes = _oStream.Read(arrbDataInput, 0, arrbDataInput.Length); //read out data, put datalength in "bytes" 
        Array.Resize(ref arrbDataInput, bytes);     // resize array to length of received data 

        _oStream.Close();          // close the network stream 

        if (arrbDataInput.Length > 0) 
        { 
         byte[] arrbMessageDecrypted = DecryptedFrame(arrbDataInput, sKey); 

         if (CheckBusy(arrbMessageDecrypted)) 
         throw new ArgumentNullException(); 

         return arrbMessageDecrypted; 
        } 
        return null;         // return the received data 
       } 
      } 
      catch (ArgumentNullException e) 
      { 
       return Sendmessage(arrbMessage); 
      } 
      catch (SocketException e) 
      { 
      } 
      catch (System.IO.IOException e) 
      { 
       while (!_oClient.Connected) 
       { 
        Connect(); 
       } 
      } 
     else 
     { 
      while (!_oClient.Connected) 
      { 
       Connect(); 
      } 
     } 
     return null; 
    } 

J'ai eu beaucoup de difficultés en laissant le flux ouvert, donc au moment où nous fermons chaque fois après l'envoi et la réception de données. Dois-je laisser le flux et tcpclient ouverts? la fonction est appelée régulièrement.

Répondre

4

Je travaille sur une application dans laquelle le NetworkStream a été ouvert lorsque l'application a commencé et a été fermé que dans les scénarios suivants:

  • application a été fermée - (cette application fonctionne principalement en continu pendant des mois).
  • connexion réseau est perdue - (Gigabit Ethernet très fiable + 100 + Mbps MPLS) après le délai, la propriété tcpClient.Connected retournera false et nous fermer la NetworkStream et TcpClient. Ensuite, nous commençons un par seconde minuterie qui va vérifier la disponibilité du serveur et que dès que le serveur se trouve, il se reconnecte ouvrant ainsi la TcpClient et NetworkStream
  • Server est en cours d'arrêt - serveur (très très rare) envoie la Déconnectez le signal qui provoque la fermeture de l'application cliente NetworkStream et TcpClient et démarrez le thread d'interrogation pour vérifier la disponibilité du serveur.

Nous n'avons pas observé de problème pour maintenir NetworkStream et TcpClient ouverts. Il existe peut-être d'autres parties du code qui peuvent causer des problèmes.


Hors contexte, mais une suggestion: Lorsque vous lisez NetworkStream, vous lisez ony 256 octets; Que faire si les données sont plus longues que 256 octets?

Je suggère un séparateur pour chaque ensemble de données; par exemple. Si votre système de chiffrement génère des hachages Base64, vous pouvez utiliser ';' en toute sécurité (point-virgule) en tant que séparateur de données. (Nous utilisons \ n comme séparateur de commandes) mais cela dépend totalement de votre scénario.

Utilisez également le type de logique suivant pour lire et stocker la chaîne reçue, et décrypter et exécuter uniquement lorsque le caractère de séparation est disponible. Cela garantira que vous ne recevez jamais une chaîne de partie et tentez un décryptage de celle-ci.

string allPendingCommands = ""; 
string commandSeparator = ";"; // your command separator character here 

while(tcpClient.Connected) 
{ 
    if (!networkStream.DataAvailable) 
     System.Threading.Thread.Sleep(100); 
     // you can change it depending on the frequency of availability of data 

    // read 256 bytes into you array 
    // convert the byte[] to string 
    // add the newly read text to the text remaining from previous command execution. 
    allPendingCommands += theReadBytes; 

    while(allPendingCommands.Contains(commandSeparator)) 
    { 
     // it may happen that the string at the moment contains incomplete 
     // string, which can also not be decoded/decrypted. This loop will 
     // stop and the next 256 bytes (as much available) will be read and 
     // appended into allPendingCommands. When the command gets completed, 
     // allPendingCommands will contain the separator character and the 
     // command will be properly decoded and executed. 

     int idx = allPendingCommands.IndexOf(commandSeparator); 
     string command = allPendingCommands.SubString(0, idx); 
     allPendingCommand = allPendingCommand.SubString(idx + 1); 

     // convert those bytes back to string (after decrypting/decoding) 
     command = Decrypt(command); 

     // Process the Command (command); // do the needful in the function 
    } 
} 
Questions connexes