|
Apache commons 系列的HttpClient 相信大家都用過,選擇它而非JDK 的java.net.HttpURLConnection ,是為了使用HttpClient 封裝的幾個實用的功能。 目前使用最多的版本還是httpclient-3.x ,在官網(wǎng)http://hc./httpclient-3.x/tutorial.html 有這么一段示例代碼: 大部分人也是以這個為規(guī)范來使用的,但是注意有一段關于“Release the Connection”的說明: 我看得也不是很明白,意思是我們必須在使用后調(diào)用來告訴HttpClient 這個連接可以重用了。這個在串行的處理中或許很有用,但是我所遇到的情況是多線程并發(fā)下,不能共享同一個HttpClient 實例,按照官方示例寫好代碼后,程序跑起來似乎沒什么問題,但是隨著時間的累計,有一天突然發(fā)現(xiàn)這個模塊不工作了,查看了一下當前的網(wǎng)絡連接,這個java 程序同一個地址保持著200多個CLOSE_WAIT 的連接,好吧,連接沒有釋放。 為什么沒有釋放?查看doc,有這樣的說明: 注意最后一句,如果該連接可以重用則不關閉,是“可以重用”,當然可以重用了,就在那兒等著我去重用,可是我都是新建的實例,怎么重用 查看源碼,找到HttpClient 的構(gòu)造方法,有一個可以指定HttpConnectionManager ,然后這個HttpConnectionManager 又有一個實現(xiàn)的構(gòu)造: 顯然alawaysClose 的默認值是false ,在釋放后連接并不總是會關閉。 所以,必須 Java代碼
大部分人使用HttpClient都是使用類似上面的事例代碼,包括Apache官方的例子也是如此。最近我在使用HttpClient是發(fā)現(xiàn)一次循環(huán)發(fā)送大量請求到服務器會導致APACHE服務器的鏈接被占滿,后續(xù)的請求便排隊等待。 我服務器端APACHE的配置 Java代碼
因此這樣的配置就會導致每個鏈接至少要過180S才會被釋放,這樣在大量請求訪問時就必然會造成鏈接被占滿,請求等待的情況。 在通過DEBUH后發(fā)現(xiàn)HttpClient在method.releaseConnection()后并沒有把鏈接關閉,這個方法只是將鏈接返回給connection manager。如果使用HttpClient client = new HttpClient()實例化一個HttpClient connection manager默認實現(xiàn)是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有個構(gòu)造函數(shù)如下 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鏈接的方法。下面再介紹由服務器端自動關閉鏈接的方法。 方法四: 代碼實現(xiàn)很簡單,所有代碼就和最上面的事例代碼一樣。只需要在HttpMethod method = new GetMethod("http://www.");加上一行HTTP頭的設置即可 Java代碼
看一下HTTP協(xié)議中關于這個屬性的定義: 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 現(xiàn)在再說一下客戶端關閉鏈接和服務器端關閉鏈接的區(qū)別。如果采用客戶端關閉鏈接的方法,在客戶端的機器上使用netstat –an命令會看到很多TIME_WAIT的TCP鏈接。如果服務器端主動關閉鏈接這中情況就出現(xiàn)在服務器端。 參考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的狀態(tài)會出現(xiàn)在主動關閉鏈接的這一端。TCP協(xié)議中TIME_WAIT狀態(tài)主要是為了保證數(shù)據(jù)的完整傳輸。具體可以參考此文檔: http://www.softlab./facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7 另外強調(diào)一下使用上面這些方法關閉鏈接是在我們的應用中明確知道不需要重用鏈接時可以主動關閉鏈接來釋放資源。如果你的應用是需要重用鏈接的話就沒必要這么做,使用原有的鏈接還可以提供性能。 |
|
|
來自: 關平藏書 > 《javaScore》