大部分人使用HttpClient都是使用类似上面的事例代码,包括Apache官方的例子也是如此。最近我在使用HttpClient是发现一次循环发送大量请求到服务器会导致APACHE服务器的链接被占满,后续的请求便排队等待。

我服务器端APACHE的配置 

 
  
  1. Timeout 30   
  2. KeepAlive On   #表示服务器端不会主动关闭链接   
  3. MaxKeepAliveRequests 100   
  4. KeepAliveTimeout 180    

 因此这样的配置就会导致每个链接至少要过180S才会被释放,这样在大量请求访问时就必然会造成链接被占满,请求等待的情况。

在通过DEBUH后发现HttpClientmethod.releaseConnection()后并没有把链接关闭,这个方法只是将链接返回给connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManagerSimpleHttpConnectionManager有个构造函数如下

 
  
  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()这样实例化一个clientconnection manager是这样被实例化的 

因此alwaysClose默认是false,connection是不会被主动关闭的,因此我们就有了一个客户端关闭链接的方法。

方法一:把事例代码中的第一行实例化代码改为如下即可,在method.releaseConnection();之后connection manager会关闭connection 

 
  
  1. HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );  

方法二:

实例化代码使用:HttpClient client = new HttpClient();

method.releaseConnection();之后加上

 
  
  1. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown(); 

方法三: 

 实例化代码使用:HttpClient client = new HttpClient();

 method.releaseConnection();之后加上 ,client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下:

 
  
  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头的设置即可

 
  
  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_WAITTCP链接。如果服务器端主动关闭链接这中情况就出现在服务器端