静态 HttpClient 仍在创建 TIME_WAIT tcp 端口 [英] Static HttpClient still creating TIME_WAIT tcp ports

查看:33
本文介绍了静态 HttpClient 仍在创建 TIME_WAIT tcp 端口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 .NET Framework(4.5.1+、4.6.1 和 4.7.2)的 HttpClient 时遇到了一些有趣的行为.由于 TCP 端口使用率高的已知问题,我在工作中的项目中提出了一些更改,不要在每次使用时处理 HttpClient,请参阅 https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.

I am experiencing some interesting behavior with the HttpClient from the .NET Framework (4.5.1+, 4.6.1 and 4.7.2). I have proposed some changes in a project at work to not dispose of the HttpClient on each use because of the known issue with high TCP port usage, see https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.

我调查了更改以检查一切是否按预期工作,并发现我们仍然遇到与以前相同的 TIME_WAIT 端口.

I have investigated the changes to check that things were working as expected and found that we are still experiencing the same TIME_WAIT ports as before.

为了确认我提议的更改是正确的,我向应用程序添加了一些额外的跟踪,以确认我在整个应用程序中使用的是 HttpClient 的相同实例.从那以后,我使用了简单的测试应用程序(取自上面链接的 aspnetmonsters 站点.

To confirm that my proposed changes were correct I have added some extra tracing to the application that confirm that I am using the same instance of the HttpClient through out the application. I have since used simple test application (taken from the aspnetmonsters site linked above.

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 身份验证(问题再次发生),我可以轻松重现该问题.

The issue only occurs when connecting to a site that is hosted in IIS using Windows Authentication. I can reproduce the issue easily by setting the Authentication to Anonymous (problem goes away) and back to Windows Authentication (problem reoccurs).

Windows 身份验证的问题似乎不仅限于提供程序的范围.如果您使用 Negotiate 或 NTLM,它也有同样的问题.如果机器只是工作站或域的一部分,也会出现此问题.

The issue with Windows Authentication does not seem to be limited to the scope of the provider. It has the same issue if you us Negotiate or NTLM. Also the issue occurs if the machine is just a workstation or part of a domain.

出于兴趣,我创建了一个 dotnet core 2.1.0 控制台应用程序,该问题根本不存在并且按预期工作.

Out of interest I created a dotnet core 2.1.0 console app and the issue is not present at all and works as expected.

TLDR:有没有人知道如何解决这个问题,或者它可能是一个错误?

TLDR: Does any one have any idea on how to fix this, or is it likely to be a bug?

推荐答案

简短版本

如果要重用具有 NTLM 身份验证的连接,请使用 .NET Core 2.1

Use .NET Core 2.1 if you want to reuse connections with NTLM authentication

长版

我很惊讶地看到老"使用 NTLM 身份验证时,HttpClient 确实为每个请求使用不同的连接.这不是错误 - 在 .NET Core 2.1 HttpClient 使用 HttpWebRequest 之前,它会在每次 NTLM 身份验证调用后关闭连接.

I was quite surprised to see that the "old" HttpClient does use a different connection for each request when NTLM authentication is used. This isn't a bug - before .NET Core 2.1 HttpClient would use HttpWebRequest which closes the connection after every NTLM authenticated call.

这在 HttpWebRequest.UnsafeAuthenticatedConnectionSharing 属性,可用于启用连接共享:

This is described in the documentation of the HttpWebRequest.UnsafeAuthenticatedConnectionSharing property which can be used to enable sharing of the connection :

该属性的默认值为false,这会导致在请求完成后关闭当前连接.每次发出新请求时,您的应用程序都必须经过身份验证序列.

The default value for this property is false, which causes the current connection to be closed after a request is completed. Your application must go through the authentication sequence every time it issues a new request.

如果此属性设置为 true,则用于检索响应的连接在执行身份验证后保持打开状态.在这种情况下,将此属性设置为 true 的其他请求可以使用该连接而无需重新进行身份验证.

If this property is set to true, the connection used to retrieve the response remains open after the authentication has been performed. In this case, other requests that have this property set to true may use the connection without re-authenticating.

风险在于:

如果用户 A 的连接已经通过身份验证,则用户 B 可以重用 A 的连接;用户 B 的请求是根据用户 A 的凭据完成的.

If a connection has been authenticated for user A, user B may reuse A's connection; user B's request is fulfilled based on the credentials of user A.

如果了解风险,并且应用程序使用模拟,则可以使用 WebRequestHandler 并设置 UnsafeAuthenticatedConnectionSharing,例如:

If one understands the risks, and the application doesn't use impersonation, one could configure HttpClient with a WebRequestHandler and set the UnsafeAuthenticatedConnectionSharing, eg :

HttpClient _client;

public void InitTheClient()
{
    var handler=new WebRequestHandler
                { 
                    UseDefaultCredentials=true,
                    UnsafeAuthenticatedConnectionSharing =true
                };
    _client=new HttpClient(handler); 
}

WebRequestHandler 不会公开 HttpWebRequest.ConnectionGroupName 允许对连接进行分组,例如通过 ID,因此它无法处理模拟.

WebRequestHandler doesn't expose the HttpWebRequest.ConnectionGroupName that would allow to group connections eg by ID, so it can't handle impersonation.

.NET Core 2.1

HttpClient 已在 .NET Core 2.1 中重写,并使用套接字实现所有 HTTP、网络功能、最小分配、连接池等.它还处理 NTLM 质询/响应流程 分开所以相同的套接字连接可用于服务不同的经过身份验证的请求.

HttpClient was rewritten in .NET Core 2.1 and implements all the HTTP, networking functionality using sockets, minimal allocations, connection pooling etc. It also handles the NTLM challenge/response flow separatelly so the same socket connection can be used to serve different authenticated requests.

如果有人感兴趣,您可以追逐从 HttpClient 到 SocketsHttpHanlder 到 HttpConnectionPoolManager 、HttpConnectionPool、HttpConnection、AuthenticationHelper.NtAuth 的调用,然后返回到 HttpConnection 以发送原始字节.

If anyone is interested, you can chase the calls from HttpClient to SocketsHttpHanlder to HttpConnectionPoolManager , HttpConnectionPool, HttpConnection, AuthenticationHelper.NtAuth and then back to HttpConnection to send the raw bytes.

这篇关于静态 HttpClient 仍在创建 TIME_WAIT tcp 端口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆