【问题标题】:All the ports on my server are used up, what am I doing wrong?我服务器上的所有端口都用完了,我做错了什么?
【发布时间】:2014-11-18 23:51:28
【问题描述】:

我有一台运行 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

【问题讨论】:

  • 这是一道 c# 编程题,还是一般的计算机网络题?
  • @gunr2171 特定于 .NET 中的 HttpClient,使用 C# 编码。我想知道我是否应该关闭连接(如果是,如何关闭)。这些是我的应用程序正在建立的连接,我相信这是一个编码问题。
  • 那你应该贴一些代码给我们看看! :)
  • 也许贴一些连接代码?猜测时很难诊断。附带说明一下,您应该始终在完成连接后关闭它们。
  • 我记得,在 WCF 中关闭传出 TCP 套接字并不会立即释放它 - 操作系统会在预期后续请求时保持打开状态。生成大量传出 WCF 调用的应用程序需要执行自己的 TCP 连接池,以防止出现端口耗尽的情况。如果你用谷歌搜索“.net TCP Port Exhaustion”,你会发现一些材料涵盖了这一点。它可能与您所看到的有关 - TCP 端口不会因为您的代码关闭它们而关闭...

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


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    相关资源
    最近更新 更多