【问题标题】:dotnet core 2.1 httpclient System.Net.Sockets.SocketExceptiondotnet core 2.1 httpclient System.Net.Sockets.SocketException
【发布时间】:2020-03-22 08:39:59
【问题描述】:

自 2 周以来,通过尝试连接我们的后端系统,我们有时会遇到以下异常:

System.Net.Http.HttpRequestException:未知错误 -1 ---> System.Net.Sockets.SocketException:System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32 端口,CancellationToken cancelToken)出现未知错误 -1 ) --- 内部异常堆栈跟踪结束 --- 位于 System.Threading.Tasks.ValueTask`1.get_Result() 的 System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancelToken) 处

但此时,我可以通过 Postman 调用 API Server。 我调用 API 服务器的代码是这样的:

using (var client = this.ClientFactory(serviceUserName, serviceUserPassword))
{
    try
    {
        using (var response = await client.SendAsync(request, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
        {
            return checkAction(response);
        }
    }
    catch (HttpRequestException ex)
    {
        this.logger.LogError(ex, "http error occured while checking availability for " + url);
        return false;
    }
    catch (TaskCanceledException ex)
    {
        this.logger.LogError(ex, url + " timed out");
        return false;
    }
    catch (Exception ex)
    {
        this.logger.LogError(ex, url + " general exception!");
        return false;
    }
}

ClientFactory() 函数的样子

private HttpClient ClientFactory(string serviceUserName, string serviceUserPassword)
{
    var client = new HttpClient();
    client.Timeout = TimeSpan.FromSeconds(this.clientTimeoutSeconds);
    if (!string.IsNullOrEmpty(serviceUserName) && !string.IsNullOrEmpty(serviceUserPassword))
    {
        var basicAuthToken = Convert.ToBase64String(Encoding.ASCII.GetBytes(serviceUserName + ":" + serviceUserPassword));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basicAuthToken);
    }

    return client;
}

我不知道如何调试这个问题。 该应用程序位于运行在 kestrel Web 服务器上的 Cloud Foundry 服务器上。

更新

            var client = this.ClientFactory(serviceUserName, serviceUserPassword);
        try
        {
            var response = await client.SendAsync(request, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
            return checkAction(response);
        }
        catch (HttpRequestException ex)
        {
            this.logger.LogError(ex, "http error occured while checking availability for " + url);
            return false;
        }
        catch (TaskCanceledException ex)
        {
            this.logger.LogError(ex, "availability check for " + url + " timed out");
            return false;
        }
        catch (Exception ex)
        {
            this.logger.LogError(ex, "availability check for " + url + " general exception!");
            return false;
        }

ClientFactory() 函数现在的样子

        private HttpClient ClientFactory(string serviceUserName, string serviceUserPassword)
    {
        var client = this.clientFactory.CreateClient();
        client.Timeout = TimeSpan.FromSeconds(this.clientTimeoutSeconds);
        if (!string.IsNullOrEmpty(serviceUserName) && !string.IsNullOrEmpty(serviceUserPassword))
        {
            var basicAuthToken = Convert.ToBase64String(Encoding.ASCII.GetBytes(serviceUserName + ":" + serviceUserPassword));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basicAuthToken);
        }

        return client;
    }

现在我使用构造函数注入的IHttpClientFactory:

        public MyConstructor(IHttpClientFactory clientFactory)
    {
        this.clientFactory = clientFactory;
    }

但这并没有帮助 我仍然得到上面的异常和其他异常,例如:

System.Net.Http.HttpRequestException: Too many open files in system --- System.Net.Sockets.SocketException: Too many open files in system 在 System.Net.Sockets.Socket..ctor(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) 在 System.Net.Sockets.DualSocketMultipleConnectAsync..ctor(SocketType socketType,ProtocolType protocolType) 在 System.Net.Sockets.Socket.ConnectAsync(SocketType socketType,ProtocolType protocolType,SocketAsyncEventArgs e) 在 System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32 端口,CancellationToken 取消令牌)

所以我的问题又来了,我该如何调试问题?它仅在生产时发生,并且在几个小时或几天后发生......

【问题讨论】:

标签: c# .net-core dotnet-httpclient socketexception kestrel-http-server


【解决方案1】:

您应该一直创建新的 HttpClient 实例。 你应该重复使用它。如果你不重用它,你可能会遇到套接字耗尽(以及一堆其他问题)。

https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

由于您使用的是 dotnet core,请查看 HttpClientFactory https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

因此,一个快速的解决方法是创建一个新的静态 HttpClient 而不是处置它。但是,您可能会遇到 DNS 问题,所以不要这样做https://github.com/dotnet/corefx/issues/11224

所以:使用HttpClientFactory,微软已经解决了上面提到的所有问题:)

【讨论】:

  • 但如果我重用 HttpCLient 使其成为静态,我该如何处理并行请求?
  • 使用 HttpClientFactory。而且 HttpClient 是线程安全的,所以没有问题。但正如我所说,不要让它静态,使用 HttpClientFactory。我什至把 DON'T 加粗... :)
猜你喜欢
  • 2018-06-25
  • 2018-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多