【轉】HttpClient容易忽視的細節——鏈接關閉

https://seanhe.iteye.com/blog/234759
 
 
Java代碼   收藏代碼
  1. HttpClient client = new HttpClient();  
  2. HttpMethod method = new GetMethod("http://www.apache.org");  
  3. try {  
  4.   client.executeMethod(method);  
  5.   byte[] responseBody = null;  
  6.     
  7.   responseBody = method.getResponseBody();  
  8.     
  9. catch (HttpException e) {  
  10.   // TODO Auto-generated catch block  
  11.   e.printStackTrace();  
  12. catch (IOException e) {  
  13.   // TODO Auto-generated catch block  
  14.   e.printStackTrace();  
  15. }finally{  
  16.   method.releaseConnection();  
  17.     
  18. }  

大部分人使用HttpClient都是使用相似上面的事例代碼,包括Apache官方的例子也是如此。最近我在使用HttpClient是發現一次循環發送大量請求到服務器會致使APACHE服務器的連接被佔滿,後續的請求便排隊等待。 
我服務器端APACHE的配置 
Java代碼   收藏代碼
  1. Timeout 30  
  2. KeepAlive On   #表示服務器端不會主動關閉連接  
  3. MaxKeepAliveRequests 100  
  4. KeepAliveTimeout 180   

所以這樣的配置就會致使每一個連接至少要過180S纔會被釋放,這樣在大量請求訪問時就必然會形成連接被佔滿,請求等待的狀況。 
在經過DEBUH後發現HttpClient在method.releaseConnection()後並無把連接關閉,這個方法只是將連接返回給connection manager。若是使用HttpClient client = new HttpClient()實例化一個HttpClient connection manager默認實現是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有個構造函數以下 
Java代碼   收藏代碼
  1. /** 
  2.  * The connection manager created with this constructor will try to keep the  
  3.  * connection open (alive) between consecutive requests if the alwaysClose  
  4.  * parameter is set to <tt>false</tt>. Otherwise the connection manager will  
  5.  * always close connections upon release. 
  6.  *  
  7.  * @param alwaysClose if set <tt>true</tt>, the connection manager will always 
  8.  *    close connections upon release. 
  9.  */  
  10. public SimpleHttpConnectionManager(boolean alwaysClose) {  
  11.     super();  
  12.     this.alwaysClose = alwaysClose;  
  13. }  

看方法註釋咱們就能夠看到若是alwaysClose設爲true在連接釋放以後connection manager 就會關閉鏈。在咱們HttpClient client = new HttpClient()這樣實例化一個client時connection manager是這樣被實例化的 
Java代碼   收藏代碼
  1. this.httpConnectionManager = new SimpleHttpConnectionManager();  

所以alwaysClose默認是false,connection是不會被主動關閉的,所以咱們就有了一個客戶端關閉連接的方法。 
方法一: 
把事例代碼中的第一行實例化代碼改成以下便可,在method.releaseConnection();以後connection manager會關閉connection 。 
Java代碼   收藏代碼
  1. HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );  

方法二: 
實例化代碼使用:HttpClient client = new HttpClient(); 
在method.releaseConnection();以後加上 
Java代碼   收藏代碼
  1. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();  

shutdown源代碼很簡單,看了一目瞭然 
Java代碼   收藏代碼
  1. public void shutdown() {  
  2.     httpConnection.close();  
  3. }  

方法三: 
實例化代碼使用:HttpClient client = new HttpClient(); 
在method.releaseConnection();以後加上 
client.getHttpConnectionManager().closeIdleConnections(0);此方法源碼代碼以下: 
Java代碼   收藏代碼
  1. public void closeIdleConnections(long idleTimeout) {  
  2.     long maxIdleTime = System.currentTimeMillis() - idleTimeout;  
  3.     if (idleStartTime <= maxIdleTime) {  
  4.         httpConnection.close();  
  5.     }  
  6. }  

將idleTimeout設爲0能夠確保連接被關閉。 
以上這三種方法都是有客戶端主動關閉TCP連接的方法。下面再介紹由服務器端自動關閉連接的方法。 
方法四: 
代碼實現很簡單,全部代碼就和最上面的事例代碼同樣。只須要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP頭的設置便可 
Java代碼   收藏代碼
  1. method.setRequestHeader("Connection", "close");  

看一下HTTP協議中關於這個屬性的定義: 
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, 
       Connection: close 
如今再說一下客戶端關閉連接和服務器端關閉連接的區別。若是採用客戶端關閉連接的方法,在客戶端的機器上使用netstat –an命令會看到不少TIME_WAIT的TCP連接。若是服務器端主動關閉連接這中狀況就出如今服務器端。 
參考WIKI上的說明http://wiki.apache.org/HttpComponents/FrequentlyAskedConnectionManagementQuestions 
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. 
TIME_WAIT的狀態會出如今主動關閉連接的這一端。TCP協議中TIME_WAIT狀態主要是爲了保證數據的完整傳輸。具體能夠參考此文檔: 
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7 
另外強調一下使用上面這些方法關閉連接是在咱們的應用中明確知道不須要重用連接時能夠主動關閉連接來釋放資源。若是你的應用是須要重用連接的話就不必這麼作,使用原有的連接還能夠提供性能。
相關文章
相關標籤/搜索