2014-04-30 3 views
1

Я пишу клиентское приложение (службу Windows), которое регулярно считывает данные и записывает данные на сервер. Сервер настроен так, чтобы всегда отвечать клиенту, если он понял. У меня есть следующий метод для отправки и получения:Когда закрывать tcpclient и 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; 
    } 

У меня было много трудностей, оставляя поток открытым, поэтому на данный момент мы закрываем его каждый раз после отправки и получения данных. Должен ли я оставить поток и tcpclient открытым? функция регулярно вызывается.

ответ

4

Я работал над приложением, в котором NetworkStream был открыт, когда приложение запускается и был закрыт только в следующих случаях:

  • Применение было закрыто - (это приложение в основном работает непрерывно в течение нескольких месяцев).
  • Подключение к сети - (очень надежный Ethernet гигабитного + 100 + Mbps MPLS) после тайм-аута, то tcpClient.Connected свойства вернет ложь, и закрывает NetworkStream и TcpClient. Тогда мы начинаем посекундный таймер, который будет проверять доступность сервера, и как только сервер найден, он воссоединяется тем самым открывая TcpClient и NetworkStream
  • сервер завершает работу - (очень очень редко) сервер посылает отключить сигнал, который заставляет клиентское приложение закрыть NetworkStream и TcpClient и запустить поток опроса для проверки доступности сервера.

Мы не обнаружили никаких проблем, связанных с открытием NetworkStream и TcpClient. Возможно, есть другие части кода, которые могут вызывать проблемы.


Из контекста, но предложение: Когда вы читаете из NetworkStream, вы читаете оны 256 байт; что, если данные длиннее 256 байтов?

Я бы предложил некоторый разделитель для каждого набора данных; например если ваша система шифрования генерирует хэши Base64, вы можете безопасно использовать ';' (точка с запятой) в качестве разделителя данных. (Мы используем \ n как разделитель команд), но это полностью зависит от вашего сценария.

Кроме того, используйте следующий тип логики для чтения и сохранения принятой строки и дешифрования и выполнения только при наличии символа разделителя. Это гарантирует, что вы никогда не получите строку детали и не попытаетесь ее расшифровать.

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 
    } 
} 
Смежные вопросы