vb.net - 使用 ReadAsync 时发生类型 'System.AggregateException' 的异常

标签 vb.net sockets async-await

背景:我正在使用 Visual Basic 和 VS Community 2013。我正在制作一个 Windows 窗体应用程序。用例是:用户单击按钮。这会弹出一个对话框。然后 TCP 客户端连接到远程服务器,并等待来自服务器的消息到达。每次消息到达时,对话框上都会显示文本。如果远程端关闭套接字,则应关闭该对话框。此外,用户可以单击对话框上的按钮,该按钮应关闭套接字并关闭对话框。

我的代码似乎实现了除最后一个要求之外的所有这些。当用户单击按钮关闭对话框时,我会看到通常的异常弹出窗口,其中包含文本:

An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code.
Additional information: One or more errors occurred.

选择“Break”会显示条件 T.Result = 0 被突出显示。调试器显示 T 的值为 Id = 1,Status = Faulted {7},Method = "{null}",Result = "{Not YetComputed}"

我的问题是:此错误意味着什么以及如何修复它?


以下是对话框代码的相关部分。为了简洁起见,我省略了 ShowStatus 函数,它除了更新表单上的可视控件之外什么也不做。

Imports Microsoft.VisualBasic
Imports System.Net.Sockets
Imports System.Text

Public Class FormMyDialog
    Private gRequest As String
    Private inbuf(10000) As Byte
    Private inoff As Integer
    Private serv As NetworkStream
    Private sock As System.Net.Sockets.TcpClient

    ' the main form calls this when the user clicks a button
    Public Sub Go(request As String)
        gRequest = request
        ShowDialog()
    End Sub

    ' this is the Close button I have placed on the dialog
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        sock.Close()
    End Sub

    Private Sub FormMyDialog_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
        sock = New System.Net.Sockets.TcpClient()
        ShowStatus("Connecting")
        sock.Connect("127.0.0.1", 53000)
        ShowStatus("Connected")

        serv = sock.GetStream()

        Dim outbuf As Byte() = Encoding.ASCII.GetBytes(gRequest + Chr(10))
        serv.Write(outbuf, 0, outbuf.Length)
        serv.Flush()

        inoff = 0
        ReadLoop()
    End Sub

    Private Sub ReadLoop()
        Dim readlen As Integer
        Dim T As Task(Of Integer)
        T = serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
        If T.Result = 0 Then
            sock.Close()
            Dim d As MethodNoArgs(Of Object)
            d = AddressOf Me.Close
            Me.Invoke(d)
            Return
        End If

        readlen = T.Result
        inoff = inoff + readlen
        ProcessInbuf()
        T.ContinueWith(Sub() ReadLoop())
    End Sub

    Public Delegate Sub MethodNoArgs(Of T1)()

    Private Sub ProcessInbuf()
        ' (omitted) processing that calls ShowStatus
        ' and updates inbuf and inoff
    End Sub

End Class

最佳答案

您已经注意到,AggregateException 只是对发生的多个可能异常的包装。

我不太确定为什么这个函数会失败,但这可能是由代码的奇怪结构引起的。我看到的主要问题是您没有遵循干净的 async-await 结构。通常,您不需要搞乱 ContinueWith.Result 确实可以在这里得到您想要做的事情。

关键是使用await关键字。该关键字基本上结合了 ContinueWith.Result。这意味着它会非阻塞地等待,直到异步操作完成并返回结果。

您的代码实际上可以归结为这样的内容:

Private Async Sub ReadLoop()
    Dim readlen As Integer

    Do
        readlen = Await serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
        inoff = inoff + readlen
        ProcessInbuf() 
        'maybe this should be async too, to wait until the processing is done
    Loop While readlen > 0

    sock.Close()
    Me.Close()
End Sub

使用 Await 的另一个优点是它还可以解包 AggregateException。您只需确保正确处理异常,因为 Async Sub 可能会因异常而终止,并且不会将异常返回到外部类。一旦通过第一个 Await,就会发生这种情况。但是,一旦您的代码通过了 ContinueWith,就会出现相同的“问题”。

关于vb.net - 使用 ReadAsync 时发生类型 'System.AggregateException' 的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34081152/

相关文章:

python - 安全直接连接文件传输程序

c - read()如何将32位int放在缓冲区中?

c# - 使用异步时未处理 SqlConnection

c# - 异步并等待 : multiple await expressions

VB.NET 让消息框在应用程序退出后继续存在

vb.net - 如何避免将鼠标悬停在子控件上时触发 MouseLeave 事件?

python - asyncore 套接字未正确关闭

c# - Parallel.ForEach 与 HttpClient 和 ContinueWith

vb.net - 音频文件类

c - 使用 System.security.cryptography 将使用 OpenSSL 进行公钥身份验证的 C 代码转换为 VisualBasic.NET?