2015-04-27 3 views
0

У меня есть следующий код как часть TCP сервераЧто происходит, когда выполняется GetStream.Read?

Private Sub StartTcpClient(ByVal client As TcpClient) 

    Dim bytesRead As Integer 
    Dim RxBuffer(1024) As Byte 
    Dim RxDataStr As String = "" 

    Dim BeginTime As Date = Date.Now 
    Dim CurrentTime As Date 
    Dim ElapsedTicks As Long = -1 
    'Dim elapsedSpan As New TimeSpan(elapsedTicks) 

    While True 
     bytesRead = client.GetStream.Read(RxBuffer, 0, RxBuffer.Length)'What happen here? 

     If bytesRead > 0 Or ElapsedTicks < 3 * 10000000.0 Then 'Espera hasta 3 segundos 

      CurrentTime = Date.Now 
      ElapsedTicks = CurrentTime.Ticks - BeginTime.Ticks 
      'RxDataStr = System.Text.ASCIIEncoding.ASCII.GetString(RxBuffer, 0, bytesRead) 'Original 
      RxDataStr += System.Text.ASCIIEncoding.Default.GetString(RxBuffer, 0, bytesRead) 'UTF8 

     Else 
      client.Close() 
      AckString = RxDataStr 
      AckReady = True 
      AckPending = False 
      Exit Sub 
     End If 
    End While 
End Sub 

Интересно, о том, что произойдет, когда линия GetStream.Read выполняется. Он уходит от моего кода и не возвращается, пока не будут собраны какие-либо данные или не произойдет ошибка или что-то еще?

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

+0

В общем, да, 'Stream.Read' - это блокировка чтения. Возможно, вы захотите посмотреть в async/wait, чтобы выполнить асинхронный ввод-вывод. – Alex

+0

Я использую Thread, поэтому у меня нет проблем с графическим интерфейсом, но с этой частью кода Thread. Если я использую асинхронный/ожидающий асинхронный ввод-вывод, то цикл While в коде выше не перегружает процессор? Я думаю, чтобы изменить ReceiveTimeout на 3000. –

+0

У вас [ReadAsync] (https://msdn.microsoft.com/en-us/library/hh137813 (v = vs.110) .aspx) и [BeginRead] (https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.beginread(v=vs.110).aspx) –

ответ

1

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

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

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

Если операция чтения не завершается в течение времени, указанного это свойство, операция чтения выбрасывает IOException.

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

Imports System.Diagnostics 

// ... other stuff 

Dim stream As Stream = client.GetStream 
Dim maxTime As TimeSpan = TimeSpan.FromSeconds(3) 
Dim elapsed As Stopwatch = Stopwatch.StartNew() 
Dim done As Boolean = False 

While Not done 
    Dim timeout As Long = CLng((maxTime - elapsed.Elapsed).TotalMilliseconds)) 
    If (timeout > 0) Then 
     stream.ReadTimeout = timeout 
     Try 
      bytesRead = stream.Read(RxBuffer, 0, RxBuffer.Length) 
      If bytesRead > 0 Then 'Espera hasta 3 segundos 
       RxDataStr += System.Text.ASCIIEncoding.Default.GetString(RxBuffer, 0, bytesRead) 'UTF8 
      Else 
       done = True 
      End If 
     Catch ioEx As IOException 
      If elapsed.Elapsed > maxTime Then 
       done = True ' due to read timeout 
      Else 
       Throw ' not due to read timeout, rethrow 
      End If 
     End Try 
    Else 
     done = True 
    End If 
End While 

client.Close() 
AckString = RxDataStr 
AckReady = True 
AckPending = False 

Поскольку вы делаете I/O, я также рекомендовал бы выполнять его как асинхронную операцию с использованием асинхр/ожидает и Stream.ReadAsync. В этом случае вы должны сделать все методы в вашей цепочке вызовов асинхронными/ждущими.

+0

Если окончание ReadTimeout приведет к генерации ошибки или просто возвращает 0 или -1 к bytesRead? Нет никакой серьезной проблемы. Если никаких данных не получено, потому что подпрограмма, ожидающая AckReady, проверяет длину или AckString, чтобы решить, должны ли данные обрабатываться или нет. –

+0

@E_Blue Он будет вызывать 'IOException', когда время чтения заканчивается. Я добавил блок «Try ... Catch», чтобы справиться с этим. – Alex