使用 IHttpClientFactory 立即关闭连接

Using IHttpClientFactory to immediately close connections

我正在连接到一个 API,其所有者不允许每个连接超过 1 个请求。这是非常不幸的,但我必须解决这个问题。 我可以为每个请求创建一个新的 HttpClient,但这会使我容易受到套接字耗尽的影响。因此,我正在设置 HttpClient:

DefaultRequestHeaders.ConnectionClose = true;

并通过

从 IHttpClientFactory 获取它
_httpClientFactory.CreateClient();

现在这大部分工作正常,但有一个问题。如果我循环发送后续调用,如下所示:

        for (int i = 0; i < 10; i++)
        {
            var request = _requestBuilder.BuildRequest();
            var httpClient = _httpClientFactory.CreateClient();
            var response = await httpClient.SendAsync(request);
        }

然后这有时会在关闭之前尝试重用旧连接失败。所以我的第一个问题是:如果我使用 Connection: close header?

发送请求,为什么 IHttpClientFactory 会重用旧连接

此外,我一直在查看 netstat,不出所料,在为每次调用创建一个新的 HttpClient 后,我​​得到了一堆处于 TIME_WAIT 状态的连接。但是对于上述情况,如果它没有失败,我会在 CLOSE_WAIT 中获得一个连接。如果我在这些请求的运行时查询 netstat,我可以看到当前连接的端口正在更改,但是如果打开一个新连接,旧连接将立即关闭并且它不会挂起任何状态。那么 IHttpClientFactory 实际上是如何管理它的呢?我无法通过在 HttpClientHttpResponseMessage

上调用 dispose 来立即关闭连接

I could create a new HttpClient for each request, but this would leave me vulnerable for socket exhaustion.

我建议您对每个请求使用 HttpClient。如果服务器支持 ConnectionClose(它似乎正在这样做),那么与使用 IHttpClientFactory.

相比,您将不会面临套接字耗尽的任何危险

对于现代 HTTP 服务器(允许多个请求的服务器,例如在 HTTP 1.1 中添加的...1997 年),存在套接字耗尽的危险,因为客户端通常会关闭他们的套接字,进入 TIME_WAIT 状态。因此 IHttpClientFactory 通过重用套接字 避免了套接字耗尽 。但在您的情况下,服务器不允许套接字重用,因此 IHttpClientFactory 只会增加复杂性而不会提供任何好处。

DefaultRequestHeaders.ConnectionClose = true;

为HTTP连接设置这个意味着服务器关闭套接字连接,这意味着你的本地套接字进入CLOSE_WAIT而不是TIME_WAIT。如果不清楚,这是图表;来自 Stevens 的 TCP/IP 插图:

Then this will sometimes fail trying to reuse the old connection before it's closed. So my first question is: why is IHttpClientFactory reusing the old connection if I send the request with a Connection: close header?

IHttpClientFactory 的重点是重用连接。据我所知,工厂在 ConnectionClose 周围没有任何特殊处理,因此它 假设 套接字仍然可行,因此它保留了它。然后它再次尝试使用该套接字。

失败的“有时”部分可能是由于竞争条件:我怀疑工厂正在做一些事情,比如检查套接字是否关闭,如果是,则创建一个新的;如果不是,则返回一个套接字(处于 CLOSE_WAIT 状态),然后将失败。

But for the above ,if it doesn't fail, I get a single connection in CLOSE_WAIT.

我希望工厂保持其套接字连接,因为它不知道 ConnectionClose

If I query netstat during runtime of these requests I can see the port is being changed for the current connection, but if a new connection is opened the old one is closed immediately and it doesn't hang in any status.

连接不能改变端口。我希望旧连接一直保留到工厂确定连接不可行时将其关闭,然后工厂立即创建一个新连接。

I couldn't get to close the connection immediately by calling dispose on either HttpClient or HttpResponseMessage

从技术上讲,工厂重用的不是 HttpClient,而是 HttpClient 包装的处理程序链中的最后一个 HttpMessageHandler。对于 factory-created 客户,当您处置 HttpClient.

时不会处置它