Java代码
-
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官方
例子就是如此。
但在使用HttpClient会发现如果不断循环发送大量请求到服务器会导致APACHE服务器的连接被占满,后续的请求便排队等待,程序陷入“假死”状态。
Java代码
-
Timeout?30??
- KeepAlive?On???#表示服务器端不会主动关闭链接 ??
-
MaxKeepAliveRequests?100??
-
KeepAliveTimeout?180???
因此这样的配置就会导致每个链接至少要过180S才会被释放,这样在大量请求访问时就必然会造成连接被占满,请求等待的情况。
在 通过DEBUG后发现HttpClient在method.releaseConnection()后并没有把连接关闭,这个方法只是将
连接返回给 connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构 造函数如下
Java代码
- ??
-
public?SimpleHttpConnectionManager(boolean?alwaysClose)?{ ??
-
????super(); ??
-
????this.alwaysClose?=?alwaysClose; ??
- }??
看 方法
注释我们就可以看到如果alwaysClose设为true在链接释放之后connection manager 就会关闭链。在我们HttpClient client = new HttpClient()这样实例化一个client时connection manager是这样被实例化的
Java代码
-
this.httpConnectionManager?=?new?SimpleHttpConnectionManager();??
因此alwaysClose默认是false,connection是不会被主动关闭的,因此我们就有了一个客户端关闭链接的方法。
方法一:把事例代码中的第一行实例化代码改为如下即可,在method.releaseConnection();之后connection manager会关闭connection 。
Java代码
-
HttpClient?client?=?new?HttpClient(new?HttpClientParams(),new?SimpleHttpConnectionManager(true)?);??
方法二:实例化代码使用:HttpClient client = new HttpClient();
在method.releaseConnection();之后加上
Java代码
- ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();??
shutdown源代码很简单,看了一目了然
Java代码
-
public?void?shutdown()?{ ??
- ????httpConnection.close(); ??
- }??
方法三:实例化代码使用:HttpClient client = new HttpClient();
在method.releaseConnection();之后加上
client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下:
Java代码
-
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代码
-
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
另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用连接时可以主动关闭连接来释放资源。如果你的应用是需要重用连接的话就没必要这么做,使用原有的连接还可以提供性能。