使用 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 实际上是如何管理它的呢?我无法通过在 HttpClient 或 HttpResponseMessage
上调用 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
.
时不会处置它
我正在连接到一个 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 实际上是如何管理它的呢?我无法通过在 HttpClient 或 HttpResponseMessage
上调用 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
.