Asp.net Core HttpClient具有许多TIME_WAIT或CLOSE_WAIT连接

时间:2019-02-28 17:54:15

标签: c# asp.net-mvc asp.net-core

我使用AddHttpClient() 依赖注入将命名客户端添加到临时服务。有时,当我在服务器上执行netstat -a时,我看到许多连接处于TIME_WAITCLOSE_WAIT状态。我相信这些连接占用了大量资源,其他TCP连接无法运行。这可能吗?有什么方法可以阻止这些安全吗?

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        ServicePointManager.DefaultConnectionLimit = 200;

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddHttpClient(FirebaseService.FirebaseServiceClient, ConfigureFirebaseClient);

        services.AddTransient<FirebaseService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();
    }

    void ConfigureFirebaseClient(HttpClient client)
    {
        var scopes = new string[] { "https://www.googleapis.com/auth/firebase.messaging" };

        Stream certificateStream = File.OpenRead("firebase-adminsdk.json");

        var serviceCredentials = GoogleCredential.FromStream(certificateStream);
        certificateStream.Close();

        var scopedCredentials = serviceCredentials.CreateScoped(scopes);
        var token = scopedCredentials.UnderlyingCredential.GetAccessTokenForRequestAsync().GetAwaiter().GetResult();
        client.SetBearerToken(token);
    }
}

public class FirebaseService
{
    public static string FirebaseServiceClient = "FirebaseServiceClient";

    private HttpClient _client;

    private readonly ILogger<FirebaseService> _logger;
    private readonly string _messagingUrl; 

    public FirebaseService(
        ILogger<FirebaseService> logger,
        IHttpClientFactory clientFactory)
    {
        _logger = logger;
        _messagingUrl = "https://fcm.googleapis.com/v1/projects/test2/messages:send";
        _client = clientFactory.CreateClient(FirebaseServiceClient);
    }

    public async Task<string> PostToFirebase(Dictionary<string, string> payload)
    {
        HttpResponseMessage result = null;
        string cont = null;
        try
        {
            var content = JsonConvert.SerializeObject(payload, Formatting.None);
            var stringContent = new StringContent(content, Encoding.UTF8, "application/json");

            result = await _client.PostAsync(_messagingUrl, stringContent);
            cont = await result.Content.ReadAsStringAsync();
            return cont;
        }
        finally
        {
            result?.Dispose();
        }
    }

}

public class ValuesController : ControllerBase
{
    private readonly IServiceProvider _serviceProvider;

    public ValuesController(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var payload = new Dictionary<string, string>();
        List<Task> tasks = new List<Task>();
        for (int i = 0; i < 100; i++)
        {
            FirebaseService firebaseService = (FirebaseService)_serviceProvider.GetService(typeof(FirebaseService));
            var task = firebaseService.PostToFirebase(payload);
            tasks.Add(task);
            Console.WriteLine(i);
        }

        await Task.WhenAll(tasks.ToArray());

        //Console.WriteLine(result);

        return Ok();
    }

}

3 个答案:

答案 0 :(得分:0)

CLOSE_WAIT-另一端关闭了连接。

TIME_WAIT-本地端点(您的应用程序)关闭了连接。

两个连接都保留几分钟,以防万一对方有一些延迟的数据包。

“我相信这些连接占用了太多资源,其他TCP连接无法运行。这可能吗?” - 我觉得不是。他们只是保持打开端口。这取决于有多少个。如果你有几百个,你会没事的。

“有没有一种方法可以阻止这些危险,安全吗?” -我不这么认为。它们都具有相同的PID,因此,如果您尝试杀死一个,则所有应用程序都将关闭。

期待更好的答案。

答案 1 :(得分:0)

我意识到遇到问题的联系并非源自client.PostAsync()。实际上,它们来自IHttpClientFactory的“客户端配置”操作中的firebase令牌身份验证请求。这就是为什么当我切换到单例或静态属性时,CreateClient(clientName)并没有被多次调用,并且问题消失了的原因。尽管这是清楚地写在文档中的,但我还是错过了。 Each time CreateClient is called, a new instance of HttpClient is created and the configuration action is called.

答案 2 :(得分:-2)

好吧,因为您可能使用了错误的生命周期管理方法。 HttpClient存在套接字耗尽问题,因此,如果可能,应将其作为单例使用。

article 将回答您的问题。另请enter link description here阅读有关DNS更改的解决方法。