【问题标题】:What happen when GetStream.Read is executed?执行 GetStream.Read 时会发生什么?
【发布时间】:2015-04-28 05:08:09
【问题描述】:

我有以下代码作为 TCP 服务器的一部分

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 秒,我需要做的是关闭当前连接。

【问题讨论】:

  • 一般是的,Stream.Read 是一个阻塞读取。你可能想看看 async/await 来做异步 I/O。
  • 我使用的是线程,所以我的 GUI 没有问题,但是使用这部分线程代码。如果我在上面的代码中使用 async/await 异步 I/O,While 循环不会超出处理器吗?我正在考虑将 ReceiveTimeout 更改为 3000。

标签: vb.net sockets tcplistener


【解决方案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,我还建议您使用 async/await 和 Stream.ReadAsync 将其作为异步操作执行。在这种情况下,您应该让调用链中的所有方法都执行异步/等待。

【讨论】:

  • 如果 ReadTimeout 完成它会产生错误或只是返回 0 或 -1 给 bytesRead?没有大问题 如果没有收到数据,因为等待 AckReady 的例程会检查长度或 AckString 来决定是否有数据要处理。
  • @E_Blue 当读取超时时它会抛出一个IOException。我添加了一个Try ... Catch 块来处理这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 2010-11-28
  • 2017-08-19
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
相关资源
最近更新 更多