【发布时间】: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