您的位置:首页 > 理论基础 > 计算机网络

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

2015-03-31 15:45 561 查看
大部分人使用HttpClient都是使用类似下面的事例代码,包括Apache官方的例子也是如此:

[java]
view plaincopyprint?

HttpClient client = new HttpClient();  
HttpMethod method = new GetMethod("http://www.apache.org");  
try {  
  client.executeMethod(method);  
  byte[] responseBody = null;  
    
  responseBody = method.getResponseBody();  
    
} catch (HttpException e) {  
  // TODO Auto-generated catch block  
  e.printStackTrace();  
} catch (IOException e) {  
  // TODO Auto-generated catch block  
  e.printStackTrace();  
}finally{  
  method.releaseConnection();  
    
}  

但最近我在使用HttpClient是发现一次循环发送大量请求到服务器会导致APACHE服务器的链接被占满,后续的请求便排队等待。

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

[java]
view plaincopyprint?

/** 
 * The connection manager created with this constructor will try to keep the  
 * connection open (alive) between consecutive requests if the alwaysClose  
 * parameter is set to <tt>false</tt>. Otherwise the connection manager will  
 * always close connections upon release. 
 *  
 * @param alwaysClose if set <tt>true</tt>, the connection manager will always 
 *    close connections upon release. 
 */  
public SimpleHttpConnectionManager(boolean alwaysClose) {  
    super();  
    this.alwaysClose = alwaysClose;  
}  

看方法注释我们就可以看到如果alwaysClose设为true在链接释放之后connection manager 就会关闭链。在我们HttpClient client = new HttpClient()这样实例化一个client时connection manager是这样被实例化的

[java]
view plaincopyprint?

this.httpConnectionManager = new SimpleHttpConnectionManager();  

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

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

[java]
view plaincopyprint?

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

方法二:

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

在method.releaseConnection();之后加上

[java]
view plaincopyprint?

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

shutdown源代码很简单,看了一目了然

[java]
view plaincopyprint?

public void shutdown() {  
    httpConnection.close();  
}  

方法三:

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

在method.releaseConnection();之后加上

client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下:

[java]
view plaincopyprint?

public void closeIdleConnections(long idleTimeout) {  
    long maxIdleTime = System.currentTimeMillis() - idleTimeout;  
    if (idleStartTime <= maxIdleTime) {  
        httpConnection.close();  
    }  
}  

将idleTimeout设为0可以确保链接被关闭。

以上这三种方法都是有客户端主动关闭TCP链接的方法。下面再介绍由服务器端自动关闭链接的方法。
方法四:

代码实现很简单,所有代码就和最上面的事例代码一样。只需要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP头的设置即可

[java]
view plaincopyprint?

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
另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用链接时可以主动关闭链接来释放资源。如果你的应用是需要重用链接的话就没必要这么做,使用原有的链接还可以提供性能。

 

原文来自:http://www.javaeye.com/topic/234759
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  httpClient