如何保持 HttpClient 连接保持活动状态?

Posted

技术标签:

【中文标题】如何保持 HttpClient 连接保持活动状态?【英文标题】:How to keep HttpClient Connection Keep-Alive? 【发布时间】:2012-12-03 04:45:01 【问题描述】:

我正在使用HttpClient POST 方法。我需要创建一次HttpClient,并且应该使用 Keep Alive Connection。但我认为在我的情况下,它每次都建立一个新的连接。

所以,我需要为HttpClient 使用 Keep Alive 连接。

这是我的代码 sn-p 任何帮助将不胜感激。

ClientConnectionManager mgr = httpclient_recv.getConnectionManager();
    hp = httpclient_recv.getParams();
    httpclient_recv = new DefaultHttpClient(
    new ThreadSafeClientConnManager(hp,mgr.getSchemeRegistry()), hp);

    while (true) 

        try 

            java.util.logging.Logger.getLogger("org.apache.http.wire")
                    .setLevel(java.util.logging.Level.FINER);
            java.util.logging.Logger.getLogger("org.apache.http.headers")
                    .setLevel(java.util.logging.Level.FINER);

            System.setProperty("org.apache.commons.logging.Log",
                    "org.apache.commons.logging.impl.SimpleLog");
            System.setProperty(
                    "org.apache.commons.logging.simplelog.showdatetime",
                    "true");
            System.setProperty(
                    "org.apache.commons.logging.simplelog.log.httpclient.wire",
                    "debug");
            System.setProperty(
                    "org.apache.commons.logging.simplelog.log.org.apache.http",
                    "debug");
            System.setProperty(
                    "org.apache.commons.logging.simplelog.log.org.apache.http.headers",
                    "debug");

            ByteArrayEntity bae = new ByteArrayEntity(byteData);
            bae.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                    "binary/octet-stream"));

            httppost_recv.setHeader(HTTP.CONN_DIRECTIVE,HTTP.CONN_KEEP_ALIVE);
            httppost_recv.setEntity(bae);



            
                System.out.println("res b4 response");
                 response_recv = httpclient_recv
                        .execute(httppost_recv);
                 response_recv.getEntity().consumeContent();
                System.out.println("res a4 response");
                if (response_recv != null) 
                    byteArray = EntityUtils.toByteArray(response_recv
                            .getEntity());
                    playing  = true;
                
                        
                 

还有 logcat 日志是:

12-03 10:07:29.466: I/System.out(1529): res b4 response
12-03 10:07:29.646: D/org.apache.http.wire(1529): >> "POST /ping HTTP/1.1[EOL]"
12-03 10:07:29.666: D/org.apache.http.wire(1529): >> "Connection: Keep-Alive[EOL]"
12-03 10:07:29.686: D/org.apache.http.wire(1529): >> "Content-Length: 1[EOL]"
12-03 10:07:29.705: D/org.apache.http.wire(1529): >> "Content-Type: binary/octet-stream[EOL]"
12-03 10:07:29.716: D/org.apache.http.wire(1529): >> "Host: 192.168.1.36[EOL]"
12-03 10:07:29.725: D/org.apache.http.wire(1529): >> "User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)[EOL]"
12-03 10:07:29.736: D/org.apache.http.wire(1529): >> "[EOL]"
12-03 10:07:29.746: D/org.apache.http.headers(1529): >> POST /ping HTTP/1.1
12-03 10:07:29.746: D/org.apache.http.headers(1529): >> Connection: Keep-Alive
12-03 10:07:29.756: D/org.apache.http.headers(1529): >> Content-Length: 1
12-03 10:07:29.756: D/org.apache.http.headers(1529): >> Content-Type: binary/octet-stream
12-03 10:07:29.765: D/org.apache.http.headers(1529): >> Host: 192.168.1.36
12-03 10:07:29.765: D/org.apache.http.headers(1529): >> User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
12-03 10:07:29.776: D/org.apache.http.wire(1529): >> "[0x0]"
12-03 10:07:29.796: D/org.apache.http.wire(1529): << "HTTP/1.1 200 OK[EOL]"
12-03 10:07:29.805: D/org.apache.http.wire(1529): << "Server: gSOAP/2.8[EOL]"
12-03 10:07:29.816: D/org.apache.http.wire(1529): << "Content-Type: binary/octet-stream[EOL]"
12-03 10:07:29.826: D/org.apache.http.wire(1529): << "Content-Length: 2048[EOL]"
12-03 10:07:29.836: D/org.apache.http.wire(1529): << **"Connection: close[EOL]"**
12-03 10:07:29.887: D/org.apache.http.headers(1529): << HTTP/1.1 200 OK
12-03 10:07:29.896: D/org.apache.http.headers(1529): << Server: gSOAP/2.8
12-03 10:07:29.896: D/org.apache.http.headers(1529): << Content-Type: binary/octet-stream
12-03 10:07:29.906: D/org.apache.http.headers(1529): << Content-Length: 2048
12-03 10:07:29.906: D/org.apache.http.headers(1529): << **Connection: close**
12-03 10:07:29.916: I/System.out(1529): res a4 response

【问题讨论】:

【参考方案1】:

10:07:29.746: D/org.apache.http.headers(1529): >> 连接:保持活动

您正在请求保持连接。

10:07:29.836: D/org.apache.http.wire(1529): "Connection: close[EOL]"

服务器拒绝它。

你对此无能为力。

【讨论】:

我在一个线程中调用整个函数......也继续发送请求并获得响应 'You are requesting keepalive' 表示您的代码是正确的,不是吗?而“你对此无能为力”对我来说似乎也很清楚。我认为不需要这些补充问题。【参考方案2】:

从 HTTP 1.1 开始,keep-alive 默认启用。如果您不希望在处理 HTTP 1.1 时显式重用它,则需要关闭连接。

对于 1.0,标题是您为此“连接:保持活动”设置的内容 这只会提示您要重用连接的服务器。当处于压力之下或出于其他原因时,服务器可能会选择不同的行为,如下所述。

对于大多数目的,这里的大多数答案都是正确的,在您添加保持活动标题的地方,它运行良好。以下说明适用于您执行此操作但仍然不起作用的情况。


服务器端问题

通常,当服务器正常运行时,答案会集中在设置上,但这并不完全正确。服务器(如Rudra)被构建为在不同情况下表现不同。 Keep-alive 附带了许多请求,服务器会在断开连接之前为您提供服务,这也是为了允许为其他人提供服务,因此在高负载的情况下,某些服务器可能会诉诸于减少 keep-alive 请求的数量为每个新连接提供服务。

从收到的最后一个请求开始也设置了超时,如果在该时间窗口内没有进一步的请求,最终将导致断开连接。很少有现代服务器可能会根据它们目前的容量来改变这一点,或者在恐慌情况下将其降至 0,从而使保持活动变得毫无意义。因此,如果您尝试连接的服务器正在经历任何此类(竞争、恐慌)情况,它可能会选择丢弃您的请求。


客户端问题

出于文档目的。 来自hc.apache.org:

HttpClient 总是尽最大努力重用连接。联系 默认情况下启用持久性,无需配置。在下面 在某些情况下,这可能会导致连接泄漏并因此丢失 资源。禁用连接持久性的最简单方法是 提供或扩展强制关闭连接的连接管理器 在 releaseConnection 方法中释放时。

HttpClient 提供了这些(阅读:琐碎的)开箱即用的东西。但是 Apache 还提供了其他一些东西,您可以添加它们来提高它的性能。

ConnectionManager(s) 例如可以为 HttpClient 定制。

因此,可以阻止保持活动/连接持久性的是您可能正在使用的连接管理器(在您的情况下这不是真的,但在其他几种情况下可能是真的)。如果您正在获取客户端对象以从某些 API 进行调用,这对您来说可能是一个完全未知/抽象的事实。下面列出了如何自定义此功能的示例(来自 Apache 连接管理文档)

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("locahost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);

CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();

(详情请咨询Apache documentation on connection management)

如果您遇到此问题,请尝试不使用 CM 或创建您自己的 HttpClient 对象。也不必为多个连接使用 CM。内置的CM足够公平。如果您发现性能下降,您可以编写自己的连接管理器。

但是,在您的情况下,您的服务器不是很支持它可能根本不支持 Keep-alive,即使您有这些标头而没有。您需要检查超时标头作为响应,在向服务器发送新请求中的 keep-alive 以确认该服务器是投诉时。

【讨论】:

***.com/questions/26137818/… @ChristopheRoussy 不太清楚你的意思是什么:),你想让我回答那个问题还是什么或者是别的什么。 连接管理代码部分好像是链接的,所以也许只是作为补充 感谢@ChristopheRoussy,我对这个答案投了反对票。显然,一个投票不明白我想要传达什么,我已经解释了更多。我希望有一天有人会给这个答案一个积极的投票。它的每一个字都是那么真实,也许复杂但真实:)【参考方案3】:

您为什么不对所有请求使用同一个客户端???

我一直在开发一个需要向许多 Web 服务请求大量数据的应用程序,为此我只使用一个静态客户端并且运行良好!

我创建了一个返回 HttpClient 的类和另一个管理我的所有请求(POST 和 GET)的类,非常简单;)

【讨论】:

客户端没有问题,如果服务器不配合,这个建议也改变不了任何东西,比如这个。

以上是关于如何保持 HttpClient 连接保持活动状态?的主要内容,如果未能解决你的问题,请参考以下文章

Facebook 聊天 tcp 连接如何保持活动状态?

如何在后台保持 iphone ios websocket 连接处于活动状态?

HttpClient 连接状态在使用一段时间后保持在 TIME_WAIT 导致 Socket Exception

IIS 回收应用程序池时如何保持 Blazor 服务器连接处于活动状态

HTTP 保持活动状态和 TCP 保持活动状态

iOS 应用程序如何在后台无限期地保持 TCP 连接处于活动状态?