2016-02-02 4 views
3

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

Мне удалось получить данные, когда они отправлены в одном сообщении за соединение. Моя проблема, похоже, заключается в том, чтобы тестировать ее с помощью telnet из командной строки. Я начну печатать, и программа будет захватывать один или два символа в зависимости от скорости ввода, а затем ничего не получит от этого потока. Я действительно не понимаю, почему. Если я поставлю thread.sleep в loop.DataAvailable, тогда он получит еще несколько символов, но снова остановится. Любая помощь приветствуется. Мой класс выглядит следующим образом:

public class TCPServer 
{ 
    private TcpListener listener; 

    public List<string> messages; 

    public TCPServer(IPAddress ip, int port) 
    { 
     try 
     { 
      messages = new List<string>(); 

      listener = new TcpListener(ip, port); 
      listener.Start(); 

      listener.BeginAcceptTcpClient(ClientConnected, listener); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
     } 
    } 

    private void ClientConnected(IAsyncResult ar) 
    { 

     TcpClient client; 
     try 
     { 
      client = listener.EndAcceptTcpClient(ar); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
      return; 
     } 

     try 
     { 
      NetworkStream stream = client.GetStream(); 
      string message = ""; 

      while (!stream.DataAvailable) 
      { 
      } 

      while (stream.DataAvailable) 
      {     
       byte[] readBytes = new byte[65536]; 
       stream.Read(readBytes, 0, readBytes.Length); 
       message += Encoding.ASCII.GetString(readBytes).TrimEnd('\0'); 
      } 

      if (message != null) 
      { 
       messages.Add(message); 
       message = ""; 
      } 
      listener.BeginAcceptTcpClient(ClientConnected, listener); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
     } 
    } 

    public void Stop() 
    { 
     listener.Stop(); 
    } 

} 

ответ

0

Так что мне удалось решить эту проблему, посмотрев больше в класс NetworkStream. В обратном вызове BeginReceiveTcpClient я извлек сетевой поток из tcpclient, чтобы получить доступ к методу async BeginReceive. Соответствующий код приведен ниже:

private void ClientConnected(IAsyncResult ar) 
    { 
     byte[] readBytes = new byte[65536]; 

     TcpClient client; 
     try 
     { 
      client = listener.EndAcceptTcpClient(ar); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
      return; 
     } 

     try 
     { 
      NetworkStream stream = client.GetStream(); 
      stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream); 

      listener.BeginAcceptTcpClient(ClientConnected, listener); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
     } 
    } 

    private void ReadStream(IAsyncResult ar) 
    { 
     try 
     { 

      NetworkStream stream = (NetworkStream)ar.AsyncState; 
      int bytesRead = stream.EndRead(ar); 

      content += Encoding.ASCII.GetString(buffer, 0, bytesRead); 
      dataProcessor.ProcessData(messages); 
      stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream); 

     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: " + ex.Message); 
     } 
    } 
2

Цикл считывания очень неверен.

Вы не понимаете, что DataAvailable не сообщает вам, сколько байтов поступит. Это дает вам нижнюю границу и может сказать 0 в любое время. Цикл будет прерван раньше. Использование DataAvailable почти всегда неверно.

Это ничего не дает и занятая ожидание, которое должно поднять красный флаг с вами:

 while (!stream.DataAvailable) 
     { 
     } 

Правильный способ читать это просто позвонить Read. Вам нужно использовать возвращаемое значение от Read, чтобы узнать, сколько байтов было получено. Обрезание нулей неверно (вы не можете получить нули таким образом) и взломать, что опять же должно поднять умственный красный флаг! Это не может быть правильным способом.

Розетки очень трудно получить. Не делайте подозрительных хаков, которые только увеличивают вероятность недетерминированных сбоев.

+0

Если это неправильный способ сделать это (как я полагаю), вы можете показать правильный путь? Это на самом деле не отвечало на вопрос. – Resistance

+0

Ну, он отвечает, почему он не работает. Вероятно, вам следует попробовать настроить цикл чтения. Если ваш протокол основан на линии, вы можете попробовать StreamReader.ReadLine. Найдите в Интернете учебник сокета (который не содержит слова DataAvailable :)). Здесь нет необходимости повторять этот контент. – usr

+0

DataAvailable является логическим в NetworkStreams, а не целочисленным значением, usr. Поэтому проверка, если это правда или ложь, определенно будет работать. ОП никогда даже не использовал его в контексте проверки количества байтов, которые нужно получить. Существует разница между 'Socket.DataAvailable' и' NetworkStream.DataAvailable'. –

 Смежные вопросы

  • Нет связанных вопросов^_^