Apache commons 系列的HttpClient 相信大家都用过,选择它而非JDK 的java.net.HttpURLConnection ,是为了使用HttpClient 封装的几个实用的功能。 目前使用最多的版本还是httpclient-3.x ,在官网http://hc./httpclient-3.x/tutorial.html 有这么一段示例代码:
大部分人也是以这个为规范来使用的,但是注意有一段关于“Release the Connection”的说明:
我看得也不是很明白,意思是我们必须在使用后调用 来告诉HttpClient 这个连接可以重用了。这个在串行的处理中或许很有用,但是我所遇到的情况是多线程并发下,不能共享同一个HttpClient 实例,按照官方示例写好代码后,程序跑起来似乎没什么问题,但是随着时间的累计,有一天突然发现这个模块不工作了,查看了一下当前的网络连接,这个java 程序同一个地址保持着200多个CLOSE_WAIT 的连接,好吧,连接没有释放。 为什么没有释放?查看doc,有这样的说明:
注意最后一句,如果该连接可以重用则不关闭,是“可以重用”,当然可以重用了,就在那儿等着我去重用,可是我都是新建的实例,怎么重用 查看源码,找到HttpClient 的构造方法,有一个可以指定HttpConnectionManager ,然后这个HttpConnectionManager 又有一个实现的构造:
显然alawaysClose 的默认值是false ,在释放后连接并不总是会关闭。 所以,必须
Java代码
大部分人使用HttpClient都是使用类似上面的事例代码,包括Apache官方的例子也是如此。最近我在使用HttpClient是发现一次循环发送大量请求到服务器会导致APACHE服务器的链接被占满,后续的请求便排队等待。 我服务器端APACHE的配置 Java代码
因此这样的配置就会导致每个链接至少要过180S才会被释放,这样在大量请求访问时就必然会造成链接被占满,请求等待的情况。 在通过DEBUH后发现HttpClient在method.releaseConnection()后并没有把链接关闭,这个方法只是将链接返回给connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构造函数如下 Java代码
看方法注释我们就可以看到如果alwaysClose设为true在链接释放之后connection manager 就会关闭链。在我们HttpClient client = new HttpClient()这样实例化一个client时connection manager是这样被实例化的 Java代码
因此alwaysClose默认是false,connection是不会被主动关闭的,因此我们就有了一个客户端关闭链接的方法。 方法一: 把事例代码中的第一行实例化代码改为如下即可,在method.releaseConnection();之后connection manager会关闭connection 。 Java代码
方法二: 实例化代码使用:HttpClient client = new HttpClient(); 在method.releaseConnection();之后加上 Java代码
shutdown源代码很简单,看了一目了然 Java代码
方法三: 实例化代码使用:HttpClient client = new HttpClient(); 在method.releaseConnection();之后加上 client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下: Java代码
将idleTimeout设为0可以确保链接被关闭。 以上这三种方法都是有客户端主动关闭TCP链接的方法。下面再介绍由服务器端自动关闭链接的方法。 方法四: 代码实现很简单,所有代码就和最上面的事例代码一样。只需要在HttpMethod method = new GetMethod("http://www.");加上一行HTTP头的设置即可 Java代码
看一下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./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./facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7 另外强调一下使用上面这些方法关闭链接是在我们的应用中明确知道不需要重用链接时可以主动关闭链接来释放资源。如果你的应用是需要重用链接的话就没必要这么做,使用原有的链接还可以提供性能。 |
|
来自: 关平藏书 > 《javaScore》