HttpClient无法从服务器获得响应

时间:2014-01-02 09:58:29

标签: java sockets httpclient

这个问题阻碍了整个团队半天!

我们使用apache httpclient 4.3.x从提供http api的存储服务器发布和获取数据。为了提高效果,我们使用了PoolingHttpClientConnectionManager

public HttpClient createHttpClient() {
    Registry registry = RegistryBuilder.create()....build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    connectionManager.setMaxTotal(50);
    connectionManager.setDefaultMaxPerRoute(50);

    CloseableHttpClient httpClient = HttpClients.custom()
       .setConnectionManager(connectionManager)
       .build();
    return httpClient;
}

然后我们在程序中保存一个httpClient实例,并将其与每个http请求重用:

全球httpClient:

HttpClient httpClient = createHttpClient();

发布一些数据:

HttpPost httpPut = new HttpPost("...");
HttpResponse response = httpClient.execute(httpPut);

// Notice we get the response content here!
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();

然后得到:

HttpGet httpGet = new HttpGet("...");

// Blocked at this line !!!!
HttpResponse response = httpClient.execute(httpGet);

String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();    

请注意以下行:// Blocked at this line !!!!

该程序在该行阻止,从未进入下一行。在调试模式下,我可以看到它已被阻止:

SocketInputStream.socketRead0()

我搜索了很多问题和文件,但没有幸运。


我的同事只需设置NoConnectionReuseStrategy.INSTANCE

即可解决问题
 HttpClients.custom()
       .setConnectionManager(connectionManager)
       // Following line fixed the problem, but why?
       .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE)
       .build();

现在它没有阻止,但为什么?

“重用连接”是什么意思?是否存在使用NoConnectionReuseStrategy

的性能问题

谢谢你们,伙计们〜

2 个答案:

答案 0 :(得分:1)

我试图重现阻止的http-get(也作为我自己的练习),但即使没有关闭响应,我也无法阻止它。我设法制作http-get块的唯一时间是执行response.getEntity().getContent()而不读取返回的InputStream并且不关闭返回的InputStream。 对于我的测试,我使用Tomcat 7.0.47和两个非常简单的servlet(一个响应“OK”来获取,另一个响应一个帖子)作为服务器。客户端启动了50个线程,每个线程执行30个交替的http-get和http-post请求(总共1500个请求)。客户端未使用RegistryBuilder,而是使用默认值(由PoolingHttpClientConnectionManager本身创建)。

关于NoConnectionReuseStrategy:默认情况下(使用HttpClients.createDefault()创建的HttpClient,我使用org.apache.httpcomponents:httpclient:4.3.1)使用连接池,最多2个连接到1个服务器。例如。即使5个线程同时向1个服务器执行各种请求,连接池也只打开2个连接,对所有请求重新使用它们,并确保在任何给定时间1个线程使用1个连接。这可以对客户端性能产生非常积极的影响,并显着降低服务器的负载。您必须确保唯一的事情是在finally块中调用response.close()(这可确保连接返回到连接池)。通过使用NoConnectionReuseStrategy,您基本上禁用了连接池:对于每个请求,将创建一个新连接。我建议您为类别org.apache.http.impl.conn.PoolingHttpClientConnectionManager启用调试日志记录,它非常有用。

关于httpPut.releaseConnection()的说明:这实际上并不释放连接,只能确保您可以在下一个请求中重复使用“httpPut”对象(请参阅apidocs,按照显示链接)。另请注意,在“httpGet”的代码中,您可以在“httpPut”而不是“httpGet”上调用releaseConnection()

答案 1 :(得分:0)

暂时回到这个问题。如果其他人遇到此问题,这篇文章可能会有用。

我正在使用Java Servlet来处理我的请求。当我使用PrintWriter实例写入响应流时,我的客户端被阻止了。尝试直接写入OutputStream response.getOutputStream.write("myresponse")并且它有效。