HttpClient容易忽视的细节——连接关闭

HttpClient如何关闭连接(转)

  1. Java代码   
  2. 1.HttpClient client = new HttpClient();     
  3. 2.HttpMethod method = new GetMethod("http://www.apache.org");     
  4. 3.try {     
  5. 4.  client.executeMethod(method);     
  6. 5.  byte[] responseBody = null;     
  7. 6.       
  8. 7.  responseBody = method.getResponseBody();     
  9. 8.       
  10. 9.} catch (HttpException e) {     
  11. 10.  // TODO Auto-generated catch block     
  12. 11.  e.printStackTrace();     
  13. 12.} catch (IOException e) {     
  14. 13.  // TODO Auto-generated catch block     
  15. 14.  e.printStackTrace();     
  16. 15.}finally{     
  17. 16.  method.releaseConnection();     
  18. 17.       
  19. 18.}    
  20. HttpClient client = new HttpClient();  
  21. HttpMethod method = new GetMethod("http://www.apache.org");  
  22. try {  
  23.   client.executeMethod(method);  
  24.   byte[] responseBody = null;  
  25.     
  26.   responseBody = method.getResponseBody();  
  27.     
  28. catch (HttpException e) {  
  29.   // TODO Auto-generated catch block  
  30.   e.printStackTrace();  
  31. catch (IOException e) {  
  32.   // TODO Auto-generated catch block  
  33.   e.printStackTrace();  
  34. }finally{  
  35.   method.releaseConnection();  
  36.     
  37. }  
  38.   
  39. 大部分人使用HttpClient都是使用类似上面的事例代码,包括Apache官方的例子也是如此。最近我在使用HttpClient是发现一次循环发送大量请求到服务器会导致APACHE服务器的链接被占满,后续的请求便排队等待。   
  40. 我服务器端APACHE的配置   
  41.   
  42. Java代码   
  43. 1.Timeout 30    
  44. 2.KeepAlive On   #表示服务器端不会主动关闭链接     
  45. 3.MaxKeepAliveRequests 100    
  46. 4.KeepAliveTimeout 180     
  47. Timeout 30  
  48. KeepAlive On   #表示服务器端不会主动关闭链接  
  49. MaxKeepAliveRequests 100  
  50. KeepAliveTimeout 180   
  51.   
  52. 因此这样的配置就会导致每个链接至少要过180S才会被释放,这样在大量请求访问时就必然会造成链接被占满,请求等待的情况。   
  53. 在通过DEBUH后发现HttpClient在method.releaseConnection()后并没有把链接关闭,这个方法只是将链接返回给connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构造函数如下   
  54.   
  55. Java代码   
  56. 1./**   
  57. 2. * The connection manager created with this constructor will try to keep the    
  58. 3. * connection open (alive) between consecutive requests if the alwaysClose    
  59. 4. * parameter is set to <tt>false</tt>. Otherwise the connection manager will    
  60. 5. * always close connections upon release.   
  61. 6. *    
  62. 7. * @param alwaysClose if set <tt>true</tt>, the connection manager will always   
  63. 8. *    close connections upon release.   
  64. 9. */    
  65. 10.public SimpleHttpConnectionManager(boolean alwaysClose) {     
  66. 11.    super();     
  67. 12.    this.alwaysClose = alwaysClose;     
  68. 13.}    
  69. /** 
  70.  * The connection manager created with this constructor will try to keep the  
  71.  * connection open (alive) between consecutive requests if the alwaysClose  
  72.  * parameter is set to <tt>false</tt>. Otherwise the connection manager will  
  73.  * always close connections upon release. 
  74.  *  
  75.  * @param alwaysClose if set <tt>true</tt>, the connection manager will always 
  76.  *    close connections upon release. 
  77.  */  
  78. public SimpleHttpConnectionManager(boolean alwaysClose) {  
  79.     super();  
  80.     this.alwaysClose = alwaysClose;  
  81. }  
  82.   
  83. 看方法注释我们就可以看到如果alwaysClose设为true在链接释放之后connection manager 就会关闭链。在我们HttpClient client = new HttpClient()这样实例化一个client时connection manager是这样被实例化的   
  84.   
  85. Java代码   
  86. 1.this.httpConnectionManager = new SimpleHttpConnectionManager();    
  87. this.httpConnectionManager = new SimpleHttpConnectionManager();  
  88.   
  89. 因此alwaysClose默认是false,connection是不会被主动关闭的,因此我们就有了一个客户端关闭链接的方法。   
  90. 方法一:   
  91. 把事例代码中的第一行实例化代码改为如下即可,在method.releaseConnection();之后connection manager会关闭connection 。   
  92.   
  93. Java代码   
  94. 1.HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );    
  95. HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );  
  96.   
  97. 方法二:   
  98. 实例化代码使用:HttpClient client = new HttpClient();   
  99. 在method.releaseConnection();之后加上   
  100.   
  101. Java代码   
  102. 1.((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();    
  103. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();  
  104. shutdown源代码很简单,看了一目了然   
  105.   
  106. Java代码   
  107. 1.public void shutdown() {     
  108. 2.    httpConnection.close();     
  109. 3.}    
  110. public void shutdown() {  
  111.     httpConnection.close();  
  112. }  
  113.   
  114. 方法三:   
  115. 实例化代码使用:HttpClient client = new HttpClient();   
  116. 在method.releaseConnection();之后加上   
  117. client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下:   
  118.   
  119. Java代码   
  120. 1.public void closeIdleConnections(long idleTimeout) {     
  121. 2.    long maxIdleTime = System.currentTimeMillis() - idleTimeout;     
  122. 3.    if (idleStartTime <= maxIdleTime) {     
  123. 4.        httpConnection.close();     
  124. 5.    }     
  125. 6.}    
  126. public void closeIdleConnections(long idleTimeout) {  
  127.     long maxIdleTime = System.currentTimeMillis() - idleTimeout;  
  128.     if (idleStartTime <= maxIdleTime) {  
  129.         httpConnection.close();  
  130.     }  
  131. }  
  132.   
  133. 将idleTimeout设为0可以确保链接被关闭。   
  134. 以上这三种方法都是有客户端主动关闭TCP链接的方法。下面再介绍由服务器端自动关闭链接的方法。   
  135. 方法四:   
  136. 代码实现很简单,所有代码就和最上面的事例代码一样。只需要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP头的设置即可   
  137.   
  138. Java代码   
  139. 1.method.setRequestHeader("Connection""close");    
  140. method.setRequestHeader("Connection""close");  
  141.   
  142. 看一下HTTP协议中关于这个属性的定义:   
  143. HTTP/1.1 defines the "close" connection option for the sender to signal that the connection will be closed after completion of the response. For example,   
  144.        Connection: close   
  145. 现在再说一下客户端关闭链接和服务器端关闭链接的区别。如果采用客户端关闭链接的方法,在客户端的机器上使用netstat –an命令会看到很多TIME_WAIT的TCP链接。如果服务器端主动关闭链接这中情况就出现在服务器端。   
  146. 参考WIKI上的说明http://wiki.apache.org/HttpComponents/FrequentlyAskedConnectionManagementQuestions   
  147. The TIME_WAIT state is a protection mechanism in TCP. The side that closes a socket connection orderly will keep the connection in state TIME_WAIT for some time, typically between 1 and 4 minutes.   
  148. TIME_WAIT的状态会出现在主动关闭链接的这一端。TCP协议中TIME_WAIT状态主要是为了保证数据的完整传输。具体可以参考此文档:   
  149. http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7   
  150. 另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用链接时可以主动关闭链接来释放资源。如果你的应用是需要重用链接的话就没必要这么做,使用原有的链接还可以提供性能。 
评论:
    1. 官方文档有建议使用空闲连接检查线程:   
    2.   
    3. Java代码   
    4. 1.import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;     
    5. 2.// 创建线程     
    6. 3.IdleConnectionTimeoutThread thread = new IdleConnectionTimeoutThread();     
    7. 4.// 注册连接管理器     
    8. 5.thread.addConnectionManager(httpClient.getHttpConnectionManager());     
    9. 6.// 启动线程     
    10. 7.thread.start();     
    11. 8.// 在最后,关闭线程     
    12. 9.thread.shutdown();    
    13. import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;  
    14. // 创建线程  
    15. IdleConnectionTimeoutThread thread = new IdleConnectionTimeoutThread();  
    16. // 注册连接管理器  
    17. thread.addConnectionManager(httpClient.getHttpConnectionManager());  
    18. // 启动线程  
    19. thread.start();  
    20. // 在最后,关闭线程  
    21. thread.shutdown();  
    22. 7 楼 sdh5724 2008-10-29   引用   
    23. 楼上的说法是对的, 但是, 性能来说, 是不合适的.   
    24. 首先, 我想问你, 既然是轮询, 为什么HttpURLConnection要每次创建.  既然是个持续的过程, 就不应该每次HttpURLConnection对象重新创建, 你应该重复使用这个对象. HttpURLConnection会持有连接的, 如果断开, 我记得他会去尝试连接.   
    25. 6 楼 SeanHe 2008-10-28   引用   
    26. kjah 写道  
    27. 但使用netstat发现很多TIME_WAIT,时间长点后会出现端口都被占用的状况 address already in use :connect,使用HttpURLConnection.disconnect()也没有效果。  
    28.   
    29. 如果你是应为客户端出现很多的TIME_WAIT造成端口占用,你不妨试一下“方法四”在HTTP请求头上设置"Connection""close"这样服务器会来主动关闭链接,这样就不会在客户端产生很多的TIME_WAIT  
    30. 5 楼 kjah 2008-10-28   引用   
    31. 我是google到这里的。。。   
    32. 您对HttpClient 的关闭分析的很透彻   
    33. 请教HttpURLConnection和URLConnection怎么关闭链接?   
    34. 我需要轮询一个网址,但使用netstat发现很多TIME_WAIT,时间长点后会出现端口都被占用的状况 address already in use :connect,使用HttpURLConnection.disconnect()也没有效果。  
    35. 4 楼 fly_ever 2008-09-11   引用   
    36. 引用  
    37.   
    38. 另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用链接时可以主动关闭链接来释放资源。如果你的应用是需要重用链接的话就没必要这么做,使用原有的链接还可以提供性能。   
    39.   
    40.   
    41. 正如你所说,实际上是只有并发量很高的时候才会发生链接占满的情况。   
    42. 而如果没有这么高的并发量,我们没必要去实现代码来关闭连接。   
    43. 因为我们在代码中实现主动关闭的功能的同时,也丧失了性能上的优势。   
    44. 因此,我觉得遇到这种情况,应该把设置中的keepAliveTimeout调低,显得更好一些。   
    45.   
    46. Java代码   
    47. 1.1. Timeout 30       
    48. 2.2. KeepAlive On   #表示服务器端不会主动关闭链接       
    49. 3.3. MaxKeepAliveRequests 100       
    50. 4.4. KeepAliveTimeout 180       
    51.    1. Timeout 30    
    52.    2. KeepAlive On   #表示服务器端不会主动关闭链接    
    53.    3. MaxKeepAliveRequests 100    
    54.    4. KeepAliveTimeout 180     
    55.   
    56. 不过,这里提供的HttpClient关闭的详细信息,还是很有价值的。  
    57. 3 楼 jorsef 2008-09-10   引用   
    58. 受用,非常感谢  
    59. 2 楼 SeanHe 2008-09-06   引用   
    60. HttpClient client = new HttpClient(); 如果这样进行实例化,默认使用SimpleHttpConnectionManager作为connection manager,SimpleHttpConnectionManager没有连接池,只管理一个连接  
    61. 1 楼 JavaTestJava 2008-09-05   引用   
    62. 方法二:   
    63. 实例化代码使用:HttpClient client = new HttpClient();   
    64. 在method.releaseConnection();之后加上   
    65. Java代码   
    66. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();    
    67.   
    68. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();   
    69. shutdown源代码很简单,看了一目了然   
    70. Java代码   
    71. public void shutdown() {     
    72.     httpConnection.close();     
    73. }    
    74.   
    75. public void shutdown() {   
    76.     httpConnection.close();   
    77. }   
      

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HttpClient是一个非常流行的Java库,用于发送HTTP请求和接收HTTP响应。在HttpClient中,可以使用短链接或长连接来与服务器进行通信。 短链接是指每次发送请求时都会创建一个新的连接,并在请求完成后关闭连接。这种方式适用于只需要发送少量请求的场景,每次请求都需要重新建立连接,无需维护连接状态。 长连接是指在发送请求后保持连接打开,并可以发送多个请求和接收多个响应。这样可以减少每次通信的开销,提高性能。长连接适用于需要频繁发送请求或保持与服务器的持续通信的场景。 在HttpClient中,默认情况下是使用短链接的。如果需要使用长连接,可以通过配置HttpClient连接管理器来实现。一种常见的方式是使用连接池来管理连接,可以重复利用已经建立的连接,减少连接的创建和销毁开销。 以下是使用HttpClient进行短链接和长连接的示例代码: 1. 短链接: ```java CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://example.com/api"); CloseableHttpResponse response = httpClient.execute(httpGet); // 处理响应 response.close(); httpClient.close(); ``` 2. 长连接: ```java PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); connManager.setMaxTotal(100); // 设置最大连接数 connManager.setDefaultMaxPerRoute(20); // 设置每个路由的最大连接HttpClient httpClient = HttpClients.custom() .setConnectionManager(connManager) .build(); HttpGet httpGet1 = new HttpGet("http://example.com/api/1"); CloseableHttpResponse response1 = httpClient.execute(httpGet1); // 处理响应 response1.close(); HttpGet httpGet2 = new HttpGet("http://example.com/api/2"); CloseableHttpResponse response2 = httpClient.execute(httpGet2); // 处理响应 response2.close(); // 不需要显式关闭HttpClient连接管理器会自动管理连接关闭 ``` 希望这些信息能对你有所帮助!如果你还有其他问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值