2015-01-15 3 views
0

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

Запрос отправляется и клиент действует правильно и отвечает, но мой код никогда не выходит из цикла в ответе на чтение.

Может ли клиент отвечать перед тем, как услышать? Как я могу удостовериться, что никогда не пропущу входящее сообщение?

  networkStream = tcpClient.GetStream(); 
      StreamWriter clientStreamWriter = new StreamWriter(); 
      clientStreamWriter.WriteLine(requestData); 
      clientStreamWriter.Flush(); 

      // Continuously read data on the socket and if it is more than just a ping, read the response. 
      StringBuilder sbReadBuffer = new StringBuilder(); 

      while (true) 
      { 
       String response = readresponse(timeoutOn30Seconds); 

       if (response.Length > 1 && (!response.Contains("\r\n") || response.Contains(","))) 
       { 
        break; 
       } 
      } 

      sbReadBuffer.Append(received); 

      return sbReadBuffer.ToString(); 

readResponse:

private string readresponse(Boolean timeoutOn30Seconds) 
    { 
     // Get network stream. 
     DateTime lastConTime = DateTime.Now; 
     Int32 i = 0; 

     // Start listening to stream. 
     while (!networkStream.DataAvailable) 
     { 
      Log.W("."); 
      // Only check every 10ms. 
      Thread.Sleep(10); 

      // If no response in 30mins stop listening and give an offline warning. 
      if ((DateTime.Now - lastConTime).TotalSeconds > tcpClient.ReceiveTimeout) 
      { 
       received = "CLIENT NOT FOUND"; 

       return received; 
      } 

      // Only check if application online every 1s. 
      if (i > 100) 
      { 
       if (Process.GetProcessesByName(ConfigurationManager.AppSettings["ClientName"]).FirstOrDefault() == null && Convert.ToInt32(ConfigurationManager.AppSettings["Device"]) != 680) 
       { 
        received = "CLIENT NOT FOUND"; 

        return received; 
       } 

       i = 0; 
      } 

      i++; 
     } 

     // If data has been writted to the buffer, read it out and assign output variable and return that string for length comparison. 
     byte[] receiveBuffer = new byte[tcpClient.ReceiveBufferSize]; 
     Int32 receiveCount = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length); 
     received = new ASCIIEncoding().GetString(receiveBuffer, 0, receiveCount); 

     return received; 
    } 

ответ

1

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

Лучшим способом может быть использование метода Read (чтение в байтах), чтобы знать, где данные доступны, в синхронизированный цикл; так изменить свое состояние в то время как таким образом (а затем настроить другие части)

while (networkStream.Read(receiveBuffer, 0, receiveBuffer.Length) > 0) 
    { 
     Log.W("."); 
     // Only check every 10ms. 
     Thread.Sleep(10); 

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

См. this answer, которые используют такой подход.

В основном установлен асинхронный обратный вызов, который будет срабатывать, когда данные поступают

public void StartListening() { 
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000); 

Console.WriteLine("Local address and port : {0}",localEP.ToString()); 

Socket listener = new Socket(localEP.Address.AddressFamily, 
    SocketType.Stream, ProtocolType.Tcp); 

try { 
    listener.Bind(localEP); 
    listener.Listen(10); 

    while (true) { 
     allDone.Reset(); 

     Console.WriteLine("Waiting for a connection..."); 
     listener.BeginAccept(
      new AsyncCallback(SocketListener.acceptCallback), 
      listener); 

     allDone.WaitOne(); 
    } 
} catch (Exception e) { 
    Console.WriteLine(e.ToString()); 
} 

Console.WriteLine("Closing the listener..."); 
} 

и там вы можете прочитать данные

public static void acceptCallback(IAsyncResult ar) { 
    // Get the socket that handles the client request. 
    Socket listener = (Socket) ar.AsyncState; 
    Socket handler = listener.EndAccept(ar); 

    // Signal the main thread to continue. 
    allDone.Set(); 

    // Create the state object. 
    StateObject state = new StateObject(); 
    state.workSocket = handler; 
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(AsynchronousSocketListener.readCallback), state); 
} 

Here full MSDN documentation

+0

К сожалению, я не могу переписать ядро структура приложения из-за ограничений бизнеса. Есть ли способ настроить текущий режим работы? –

+0

Я редактирую свой предыдущий ответ с другим вариантом – Luca

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

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