【发布时间】:2019-01-09 22:18:54
【问题描述】:
我在使用 .NET Framework(4.5.1+、4.6.1 和 4.7.2)的 HttpClient 时遇到了一些有趣的行为。由于 TCP 端口使用率高的已知问题,我已提议在工作中的项目中进行一些更改,以便在每次使用时不处理 HttpClient,请参阅https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/。
我调查了更改以检查是否按预期工作,发现我们仍然遇到与以前相同的 TIME_WAIT 端口。
为了确认我提出的更改是正确的,我向应用程序添加了一些额外的跟踪,以确认我在整个应用程序中使用的是同一个 HttpClient 实例。从那以后,我使用了简单的测试应用程序(取自上面链接的 aspnetmonsters 站点。
using System;
using System.Net.Http;
namespace ConsoleApplication
{
public class Program
{
private static HttpClientHandler { UseDefaultCredentials = true };
private static HttpClient Client = new HttpClient(handler);
public static async Task Main(string[] args)
{
Console.WriteLine("Starting connections");
for(int i = 0; i<10; i++)
{
var result = await Client.GetAsync("http://localhost:51000");
Console.WriteLine(result.StatusCode);
}
Console.WriteLine("Connections done");
Console.ReadLine();
}
}
}
仅在使用 Windows 身份验证连接到托管在 IIS 中的站点时才会出现此问题。我可以通过将身份验证设置为匿名(问题消失)并返回到 Windows 身份验证(问题再次发生)来轻松重现该问题。
Windows 身份验证问题似乎并不局限于提供程序的范围。如果您使用 Negotiate 或 NTLM,它也有同样的问题。如果机器只是工作站或域的一部分,也会出现此问题。
出于兴趣,我创建了一个 dotnet core 2.1.0 控制台应用程序,该问题根本不存在,并且按预期工作。
TLDR:有没有人知道如何解决这个问题,或者它可能是一个错误?
【问题讨论】:
-
不存在“TCP 端口使用率高的已知问题”。那篇文章说您不需要 处理 HttpClient,因为它是可重用且线程安全的。它还说您不应该处置它,因为它可以像 WebClient 和原始 HttpWebRequest 那样重用 SSL 通道、套接字等。您使用静态 HttpClient 是因为可以,而不是因为任何问题
-
'没有“高 TCP 端口使用率的已知问题”'。那篇文章似乎以不同的方式论证了这一点。这不是错误,因为它是预期的行为,建议不要在每个请求中处理 HttpClient。甚至 Microsoft 模式和实践也推荐相同的配置。通过简单地使用 Windows 身份验证针对 IIS 运行示例应用程序,您可以看到问题。使用 sysinternals 中的 TcpView,您可以看到每个请求在 TIME_WAIT 中剩余 1 个端口。
-
不,它没有。它并没有说 HttpClient 有问题 - 它甚至没有暗示它。它说您可以重用 HttpClient 实例并保存一些套接字。这也不是什么新鲜事,这是自 2012 年以来就为人所知的。不过,那篇文章可能是当今最受欢迎的文章
-
顺便说一句,没有复制。运行文章的代码按预期运行。使用 TcpView 表明使用静态 HttpClient 不会留下任何套接字。每次使用新的 HttpClient 运行它确实会打开 10 个套接字。在使用静态客户端运行测试之前,我必须等待这些套接字关闭
-
此外,使用静态客户端的性能要好得多,因为它不必每次都执行 DNS 查找和建立 SSL 通道。忘记插座。这是一个 100 倍的改进。 这应该足以说服任何人使用共享的 HttpClient 实例,尤其是在您进行大量 HTTP 调用时