VB.Net BeginGetResponse"请求被中止:连接意外关闭。"

时间:2017-05-04 10:29:51

标签: vb.net asynchronous

测试发送Web请求的不同方法的吞吐量,因此我创建了一个WebRequester类,它使用BeginGetResponse异步发送请求,并实现BeginGetResponse和BeginRead的回调。从我的调用代码循环发送多个请求时,如果我重用相同的HttpWebRequest对象,我会收到以下异常:

  

"请求已中止:连接意外关闭。"

如果我在调用代码For循环的每次迭代期间创建一个新的HttpWebRequest对象,则异常永远不会发生。

问题是,在每次迭代时创建一个新的HttpWebRequest会有相当显着的性能下降。这里发生了什么?

编辑:忘记提及一些事情。使用Visual Studio 2017,.NET 4.5.2,在端口8888上运行的Fiddler和在端口1337上启动的NodeJS Express测试服务器。

Imports System.Net
Imports System.Threading

Public Class Form1

    Private Sub Test() Handles Button1.Click
        'Test using HttpWebRequest.BeginGetResponse
        ServicePointManager.DefaultConnectionLimit = 2

        Dim iterations as integer = 1000
        Dim completedCount As Integer = 0
        Dim lock As New Object
        Dim mre As New ManualResetEvent(False)
        Dim wr As New WebRequester

        AddHandler wr.ResponseReceived, Sub(reqState As RequestState)
                                            SyncLock lock
                                                completedCount += 1
                                                If completedCount = iterations Then
                                                    mre.Set()
                                                End If
                                            End SyncLock
                                        End Sub

        'If I reuse the HttpWebRequest object below in my loop, I receive "The request was aborted: The connection was closed unexpectedly." :(
        'Dim req As HttpWebRequest = HttpWebRequest.Create("http://localhost.:1337/")
        'req.Proxy = New WebProxy("127.0.0.1", 8888)
        For i = 0 To iterations - 1
            Dim req As HttpWebRequest = HttpWebRequest.Create("http://localhost.:1337/")
            req.Proxy = New WebProxy("127.0.0.1", 8888)
            wr.SendRequest(req, 30000)
        Next
        mre.WaitOne()
    End Sub

End Class

Imports System.Net

Public Class RequestState

    Private bufferSize As Integer = 1024

    Public Property Request As HttpWebRequest
    Public Property Response As HttpWebResponse
    Public Property ResponseBody As String
    Public Property ResponseStream As IO.Stream
    Public Property ResponseData As Text.StringBuilder
    Public Property ReadBuffer As Byte()

    Public Sub New()
        ReadBuffer = New Byte(bufferSize) {}
        ResponseData = New System.Text.StringBuilder()
    End Sub

End Class

Imports System.Net

Public Class WebRequester

    'Adapted from https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2

    Private mre As New Threading.ManualResetEvent(False)

    Public Event ResponseReceived(reqState As RequestState)
    Public Event ExceptionRaised(ex As Exception)

    Public Sub SendRequest(req As HttpWebRequest, timeOut As Integer)
        Try
            Dim reqState As New RequestState
            reqState.Request = req
            Dim result As IAsyncResult = reqState.Request.BeginGetResponse(New AsyncCallback(AddressOf RespCallback), reqState)
            Threading.ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, New Threading.WaitOrTimerCallback(AddressOf TimeoutCallback), reqState.Request, timeOut, True)
            mre.WaitOne()
            reqState.Response.Close()
        Catch ex As Exception
            RaiseEvent ExceptionRaised(ex)
        End Try
    End Sub

    Private Sub RespCallback(asyncResult As IAsyncResult)
        Try
            Dim reqState As RequestState = asyncResult.AsyncState
            reqState.Response = reqState.Request.EndGetResponse(asyncResult)
            reqState.ResponseStream = reqState.Response.GetResponseStream
            reqState.ResponseStream.BeginRead(reqState.ReadBuffer, 0, 1024, New AsyncCallback(AddressOf ReadCallback), reqState)
        Catch ex As Exception
            RaiseEvent ExceptionRaised(ex)
        End Try
        mre.Set()
    End Sub

    Private Sub ReadCallback(asyncResult As IAsyncResult)
        Try
            Dim reqState As RequestState = asyncResult.AsyncState
            'Read the buffer, if there is more data, recursively call responseStream.BeginRead
            Dim read As Integer = reqState.ResponseStream.EndRead(asyncResult)
            If read > 0 Then
                reqState.ResponseData.Append(Text.Encoding.ASCII.GetString(reqState.ReadBuffer, 0, read))
                Dim ar As IAsyncResult = reqState.ResponseStream.BeginRead(reqState.ReadBuffer, 0, 1024, New AsyncCallback(AddressOf ReadCallback), reqState)
                Return
            Else
                'Request complete!
                reqState.ResponseBody = reqState.ResponseData.ToString
                reqState.ResponseStream.Close()
                reqState.ResponseStream.Dispose()
                RaiseEvent ResponseReceived(reqState)
            End If
        Catch ex As Exception
            RaiseEvent ExceptionRaised(ex)
        End Try
        mre.Set()
    End Sub

    Private Shared Sub TimeoutCallback(state As Object, timedOut As Boolean)
        If timedOut Then
            Dim request As HttpWebRequest = state

            If Not (request Is Nothing) Then
                request.Abort()
            End If
        End If
    End Sub 'TimeoutCallback

End Class

为了回应可能存在的问题,除了我们都在重用HttpWebRequest对象之外,我们的情况似乎有所不同,足以保证一个新问题。从技术上讲,我甚至不知道是否可以重用HttpWebRequest,我真的在问我为什么这样做,我收到了我发布的例外。

0 个答案:

没有答案