我服务器上的所有端口都用完了,我做错了什么?

时间:2014-09-24 13:04:41

标签: vb.net tcp port dotnet-httpclient netstat

我有一台运行Windows Server 2012的计算机,用于运行我的许多应用程序。他们中的大多数都是并行处理许多异步Web请求(使用.NET 4.5中的HttpClient)。

当我检查NETSTAT时,我看到几乎所有可用的端口(假设66,536是最大值)端口正在使用中。基本NETSTAT调用的管道输出是一个4mb文本文件,有64,583行。其中大部分都在TIME_WAIT中,批次不属于任何特定流程,但标记为"系统流程"。

我理解TIME_WAIT不一定是坏事,我的应用程序似乎没有明确地抛出异常,说明由于没有可用端口而无法完成请求。然而,这令我担忧,我担心它可能会导致超时。

这是预期的吗?我应该减少注册表中的TcpTimedWaitDelay值吗?我认为默认情况下连接在TIME_WAIT中保持4分钟。还有可能我在我的代码中做了一些错误的事情,让连接保持开放状态吗?我尽可能重用HttpClient对象,并在完成后始终处理它。我应该注意连接:在回复中关闭标题吗?

编辑:根据要求添加代码。这是发出请求的函数(HttpClient的自定义类包装器的一部分);

  Public Async Function WebRequestAsync(Url As String, Optional RequestMethod As RequestMethod = RequestMethod.GET, Optional Content As Object = Nothing, _
                                              Optional ContentType As ContentType = ContentType.Default, Optional Accept As String = DefaultAcceptString, _
                                              Optional AdditionalHeaders As NameValueCollection = Nothing, Optional Referer As String = Nothing, _
                                              Optional NoCache As Boolean = False, Optional CustomCookieHandler As Boolean = False, _
                                              Optional Attempts As Integer = 2, Optional CanBeCancelled As Boolean = True) _
                                   As Tasks.Task(Of HttpResponseMessage)

    If Attempts < 1 Then Attempts = 1

    Dim Method As HttpMethod = Nothing
    Select Case RequestMethod
      Case Variables.RequestMethod.DELETE : Method = HttpMethod.Delete
      Case Variables.RequestMethod.GET : Method = HttpMethod.Get
      Case Variables.RequestMethod.OPTIONS : Method = HttpMethod.Options
      Case Variables.RequestMethod.POST : Method = HttpMethod.Post
      Case Variables.RequestMethod.PUT : Method = HttpMethod.Put
    End Select

    'prepare message
    Dim Message As New HttpRequestMessage(Method, Url)
    Message.Headers.ExpectContinue = False
    Message.Headers.TryAddWithoutValidation("Accept", Accept)
    If Referer IsNot Nothing Then Message.Headers.Add("Referer", Referer)
    If NoCache Then
      Message.Headers.Add("Pragma", "no-cache")
      Message.Headers.Add("Cache-Control", "no-cache")
    End If
    If AdditionalHeaders IsNot Nothing Then
      For Each Key In AdditionalHeaders.AllKeys
        Message.Headers.TryAddWithoutValidation(Key, AdditionalHeaders(Key))
      Next
    End If

    'set content
    If Content IsNot Nothing Then
      Dim ContentTypeString As String = GetEnumDescription(ContentType)

      Dim ContentBytes As Byte() = Nothing
      If TypeOf Content Is String Then
        ContentBytes = Encoding.UTF8.GetBytes(CType(Content, String))
      ElseIf TypeOf Content Is Byte() Then
        ContentBytes = CType(Content, Byte())
      ElseIf TypeOf Content Is MultiPartPostData Then
        Dim MultiPartPostData As MultiPartPostData = CType(Content, MultiPartPostData)
        ContentBytes = MultiPartPostData.Bytes
        ContentTypeString += "; boundary=" & MultiPartPostData.Boundary
      End If

      Dim ByteArrayContent As New ByteArrayContent(ContentBytes)
      ByteArrayContent.Headers.Add("Content-Type", ContentTypeString)
      Message.Content = ByteArrayContent
    End If

    'get response
    Output(RequestMethod.ToString & " " & Url, OutputType.Debug)

    'Set cancellation token
    Dim CToken As New CancellationToken
    If CancellationToken IsNot Nothing AndAlso CancellationToken.HasValue AndAlso CanBeCancelled Then CToken = CancellationToken.Value

    Dim Response As HttpResponseMessage = Nothing
    For Attempt = 1 To Attempts
      Try
        Response = Await Client.SendAsync(Message, HttpCompletionOption.ResponseHeadersRead, CToken).ConfigureAwait(False)
      Catch ex As Tasks.TaskCanceledException
        If DebugMode Then Output(Method.ToString & " " & Url & " Timed out", OutputType.Error)
      Catch ex As HttpRequestException
        If ex.InnerException IsNot Nothing Then
          If DebugMode Then Output(Method.ToString & " " & Url & " " & ex.InnerException.Message, OutputType.Error)
          If ex.InnerException.Message = "Timed out" Then Continue For
        Else
          If DebugMode Then Output(Method.ToString & " " & Url & " " & ex.Message, OutputType.Error)
        End If
      Catch ex As Exception
        If DebugMode Then Output(Method.ToString & " " & Url & " " & ex.Message, OutputType.Error)
      End Try

      Exit For
    Next

    If Response IsNot Nothing Then
      Output(Method.ToString & " " & Url & " " & Response.StatusCode & " " & Response.StatusCode.ToString, OutputType.Debug)
      If CustomCookieHandler AndAlso Cookies IsNot Nothing Then
        Dim Values As IEnumerable(Of String) = Nothing
        If Response.Headers.TryGetValues("Set-Cookie", Values) Then ManuallyExtractCookies(Values, New Uri(Url).GetLeftPart(UriPartial.Authority))
      End If
    End If

    Return Response
  End Function

提出请求的一个例子;

Using HttpClient As New HttpClientWrapper(User, Task)
  Dim Response As String = Await HttpClient.WebRequestStringAsync("http://www.google.com")
  If Response Is Nothing Then Return Nothing
End Using

1 个答案:

答案 0 :(得分:0)

  

在HTTP 1.1中,除非声明,否则所有连接都被视为持久连接   否则。

因此,如果您不关闭连接,服务器将继续等待新请求(至少在某个超时之前)。

解决方案是在收到响应后添加Connection: close标头或明确关闭连接:Response.Dispose()