简体   繁体   English

Http Client 4.5 没有在 Java 中使用池连接管理器重用相同的连接

[英]Http Client 4.5 not reusing the same connection using pooling connection manager in java

My below code is using pooling connection manager of apache http client 4.5 version.我下面的代码使用的是 apache http 客户端 4.5 版本的池连接管理器。 If I make a 50 requests, I am seeing in netstat 50 different tcp ports are being used, but at max using 5 connections alive any time.如果我发出 50 个请求,我会在 netstat 中看到正在使用 50 个不同的 tcp 端口,但最多可以随时使用 5 个连接。 I have seen in wire shark also having filter tcp.flags.syn==1 && tcp.flags.ack==0 it is creating 50 packets in filter, so it is using different connections rather than using the same connection, so why am not able to do?我在tcp.flags.syn==1 && tcp.flags.ack==0看到也有过滤器tcp.flags.syn==1 && tcp.flags.ack==0它在过滤器中创建 50 个数据包,所以它使用不同的连接而不是使用相同的连接,所以为什么我不能吗?

my code:我的代码:

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.glassfish.jersey.SslConfigurator;
import org.json.JSONException;
import org.json.JSONObject;

public class App3Conn {
    private static CloseableHttpClient client;


    static String target="https://example.com";

    static PoolingHttpClientConnectionManager cm ;
static{

SslConfigurator sslConfig = SslConfigurator.newInstance()
            .securityProtocol("TLS")
            .keyStoreFile("/Users/file")
            .keyStorePassword("passw")
            .keyStoreType("JKS")
            .trustStoreFile("/Users/file");

    SSLContext sslCtx = sslConfig.createSSLContext();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslCtx,NoopHostnameVerifier.INSTANCE);
    Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", sslsf)
            .build();


    cm = new PoolingHttpClientConnectionManager(r);
    cm.setMaxTotal(15);
    cm.setDefaultMaxPerRoute(5);

    client = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionManager(cm).build();


}
public static void main(String a[]) throws JSONException, ClientProtocolException, IOException
{

    JSONObject jsonMessage = new JSONObject();



    JSONObject jsonResponse;

    jsonMessage.put("keyID", "keyID" );


     StringEntity se = new StringEntity(jsonMessage.toString());
     CloseableHttpResponse response2;
    HttpPost httpPost = new HttpPost(target);
    httpPost.setEntity(se);
    httpPost.setHeader("Accept", "application/json");
    httpPost.setHeader("Content-type", "application/json");
    httpPost.setHeader("Connection", "keep-alive");
    int i;
    for(i=0;i<50;i++)
    {

        response2 = client.execute(httpPost);


     HttpEntity entity2 = response2.getEntity();
     String result = EntityUtils.toString(entity2);

     EntityUtils.consume(entity2);


     jsonResponse = new JSONObject(result);

    String text = jsonResponse.getString("result");


    response2.close();
    }
}
}

I've seen this one before.我以前见过这个。 It was down to the way that the Apache connection pool works.这取决于 Apache 连接池的工作方式。 An opaque state member is associated with the pool entry and must match to the requested state when a pool entry is requested (leased).不透明state成员与池条目相关联,并且在请求(租用)池条目时必须与请求的状态匹配。

When a connection lease attempt is made the state requested is null .当进行连接租用尝试时,请求的statenull However when the connection is put back into the pool the state is set to the X500Principal object of the SSL peer.但是,当连接放回池中时, state将设置为 SSL 对等方的X500Principal对象。 This happens in the DefaultUserTokenHandler class.这发生在DefaultUserTokenHandler类中。 Luckily this is overridable when we create the HttpClient class.幸运的是,当我们创建HttpClient类时,这是可以覆盖的。 Here's an example:下面是一个例子:

HttpClient apacheHttpClient = HttpClients.custom()
    .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy())
    .setConnectionManager(new PoolingHttpClientConnectionManager(r))
    .setUserTokenHandler(new UserTokenHandler() {
      @Override
      public Object getUserToken(HttpContext context) {
        return null;
      }
    })
    .build();

Do check that you're not losing anything that you depend on from DefaultUserTokenHandler and don't use this method if the HttpClient that you create can connect to multiple SSL peers through the same HTTP route.如果您创建的HttpClient可以通过相同的 HTTP 路由连接到多个 SSL 对等点,请检查您是否丢失了您依赖于DefaultUserTokenHandler任何内容,并且不要使用此方法。 In my case this client is used to connect to a single SSL server.在我的情况下,此客户端用于连接到单个 SSL 服务器。

When you want to reuse the pool connection, don't close the response.当你想重用池连接时,不要关闭响应。 no need of response2.close();不需要 response2.close(); response.close() closes all input/output resources and at last, closes tcp connection(socket). response.close() 关闭所有输入/输出资源,最后关闭 tcp 连接(套接字)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM