2015-07-03 3 views
4

Это конкретный вопрос о том, что происходит в фоновой связи NetworkStream, потребляющей необработанные данные через TCP. Соединение TcpClient взаимодействует напрямую с аппаратным устройством в сети. Каждый раз так часто, в случайные моменты времени, NetworkStream появляется с икотой и может быть лучше всего описан при наблюдении в режиме отладки. У меня есть тайм-аут чтения, установленный в потоке, и когда все работает так, как ожидалось, при переходе через Stream.Read, он будет сидеть там и ждать длины таймаута для входящих данных. Когда нет, поступает только небольшая часть данных, TcpClient по-прежнему отображается как открытый и подключенный, но Stream.Read больше не ждет периода ожидания для входящих данных. Он сразу переходит к следующей строке, никакие данные не получены явно, и никакие данные никогда не появятся до тех пор, пока все не будет удалено, и новое соединение будет восстановлено.TCP Socket/NetworkStream неожиданно сбой

Вопрос в этом конкретном сценарии, какое состояние является NetworkStream в этой точке, что его вызывает, и почему соединение TcpClient все еще находится в кажущемся открытом и действительном состоянии? Что происходит в фоновом режиме? Нет ошибок, которые были сброшены и захвачены, является ли поток бесшумным сбоем в фоновом режиме? В чем разница между состояниями TcpClient и NetworkStream?

private TcpClient Client; 
private NetworkStream Stream; 

Client = new TcpClient(); 
var result = Client.BeginConnect(IPAddress, Port, null, null); 
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2)); 
Client.EndConnect(result); 
Stream = Client.GetStream(); 

try 
{ 
    while (Client.Connected) 
    { 
     bool flag = true; 
     StringBuilder sb = new StringBuilder(); 

     while (!IsCompleteRecord(sb.ToString()) && Client.Connected) 
     { 
      string response = ""; 
      byte[] data = new byte[512]; 

      Stream.ReadTimeout = 60000; 

      try 
      { 
       int recv = Stream.Read(data, 0, data.Length); 
       response = Encoding.ASCII.GetString(data, 0, recv); 
      } 
      catch (Exception ex) 
      { 

      } 

      sb.Append(response); 
     } 

     string rec = sb.ToString(); 
     // send off data 
     Stream.Flush(); 
    } 
} 
catch (Exception ex) 
{ 

} 

ответ

0

Вы не правильно тестируете партнера, закрывающего его конец.

С этой ссылке: https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.

Вы просто делаете stream.read, а не интерпретировать тот факт, что вы, возможно, получили 0 байт, что означает, что партнер закрыл конец связи. Это называется половиной. Он больше не отправит вам. В этот момент вы также должны закрыть конец разъема.

Существует пример доступен здесь:
https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx

// Read data from the remote device. 
int bytesRead = client.EndReceive(ar); 

if (bytesRead > 0) { 
    // There might be more data, so store the data received so far. 
    state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); 

    // Get the rest of the data. 
    client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, 
       new AsyncCallback(ReceiveCallback), state); 
} else { 
    // All the data has arrived; put it in response. 
    if (state.sb.Length > 1) { 
     response = state.sb.ToString(); 
    } 
    // Signal that all bytes have been received. 
    receiveDone.Set(); ---> not that this event is set here 
} 

и в главном блоке кода он ждет receiveDone:

receiveDone.WaitOne(); 

// Write the response to the console. 
Console.WriteLine("Response received : {0}", response); 

// Release the socket. 
client.Shutdown(SocketShutdown.Both); 
client.Close(); 

Вывод: проверка на получение 0 байт и закройте конец сокета, потому что это то, что сделал другой конец.

Тайм-аут обрабатывается с исключением. Вы не делаете ничего с таймаутом, потому что ваш блок catch пуст. Вы просто продолжаете пытаться получить.

+0

Спасибо за вклад, Филипп! Существует много логики, которые я извлек из фрагмента кода для ясности, чтобы выделить, где возникла проблема. –

+0

Я подозревал, что вы сказали, но я должен уточнить. Закрытие удаленного хоста не должно происходить; это неожиданно. В этом случае удаленный хост отправляет часть передачи и неожиданно закрывается. Я ищу идентификатор, который приходил бы через провод, чтобы определить, в каком состоянии находится удаленный хост во время сбоя.Есть ли дополнительная команда или пакет низкого уровня, который я мог бы идентифицировать во время закрытия, или определенное состояние потока, которое я ищу на стороне .net? Мне нужно собрать как можно больше информации для производителя. –

+0

Я использую wirehark, чтобы проверить, что происходит на проводе. Когда соединение TCP закрывается, происходит четырехстороннее рукопожатие. Партнер должен инициировать его, отправив FIN. Ваша сторона TCP будет поддерживать его, а когда вы закроете сокет, вы также отправите FIN, чтобы партнер мог. –

0

@Philip уже ответил на вопрос.
Я просто хочу добавить, что я рекомендую использовать SysInternals TcpView, который в основном представляет собой графический интерфейс для netstat и позволяет вам легко проверять состояние всех сетевых подключений вашего компьютера.
Об обнаружении состояния подключения в вашей программе, см. here in SO.

+0

Сладкий, спасибо. Оба они определенно помогут мне! –

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