dotnet核心2.1 httpclient System.Net.Sockets.SocketException

时间:2019-11-26 20:56:20

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

由于尝试连接后端系统2周以来,我们收到以下异常:

  

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

但是现在,我可以通过邮递员调用API服务器。 我的调用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:系统中打开的文件太多--- System.Net.Sockets.SocketException:系统中打开的文件太多      在System.Net.Sockets.Socket..ctor(AddressFamily addressFamily,SocketType套接字类型,ProtocolType协议类型)      在System.Net.Sockets.DualSocketMultipleConnectAsync..ctor(SocketType套接字类型,ProtocolType协议类型)      在System.Net.Sockets.Socket.ConnectAsync(SocketType套接字类型,ProtocolType协议类型,SocketAsyncEventArgs e)      在System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32端口,CancelationToken cancelToken)

所以我的问题再次出现,如何调试该问题?它仅在产品上以及数小时或数天之后出现。

1 个答案:

答案 0 :(得分:0)

您应该始终创建一个新的HttpClient实例。 您应该重用它。如果不重用它,则会遇到套接字耗尽(以及其他一系列问题)。

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

由于您使用的是dotnet核心,因此请查看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,微软已经解决了上面提到的所有问题:)