httpclient是java開發中非常常見的一種訪問網絡資源的方式了,本位主要說明多線程環境下HttpClient連接池的使用。
雖說http協議時無連接的,但畢竟是基於tcp的,底層還是需要和服務器建立連接的。對於需要從同一個站點抓取大量網頁的程序,應該使用連接池,否則每次抓取都和Web站點建立連接、發送請求、獲得響應、釋放連接,一方面效率不高,另一方面稍不小心就會疏忽了某些資源的釋放、導致站點拒絕連接(很多站點會拒絕同一個ip的大量連接、防止DOS攻擊)。
HttpClient從4.2開始拋棄了先前的SingleClientConnManager和ThreadSafeConnManger,取而代之的是BasicClientConnectionManager和PoolingClientConnectionManager。
BasicClientConnectionManager內部只維護一個活動的connection,儘管這個類是線程安全的,但是最好在一個單獨的線程中重複使用它。如果在同一個BasicClientConnectionManager對象中,多次執行http請求,後繼請求與先前請求是同一個route,那麼BasicClientConnectionManager會使用同一個連接完成後續請求,否則,BasicClientConnectionManager會將先前的connection關閉,然後爲後續請求創建一個新的連接。換句話說,BasicClientConnectionManager會盡力複用先前的連接(注意:創建連接和銷燬連接都是不小的開銷),因此,如果對同一個service有多個連續請求,應該儘量使用同一個BasicClientConnectionManager完成。
PoolingClientConnectionManager可以在多線程中使用,連接按照route被緩存(pooled),當後續的請求route已經在pool中存在,就會使用pool中先前使用的connection獲取請求結果。PoolingClientConnectionManager對每個router維護的connection數目有上限要求,默認情況下,每個router最多維護兩個併發線程的connection連接,整個pool最多容納20個併發的connections。當然可以通過設置來修改這些限制。
BasicClientConnectionManager的示例:
public static void basicClientTest() throws ClientProtocolException, IOException{
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://m.weather.com.cn/data/101010100.html");
HttpResponse response = httpClient.execute(httpGet);
String result = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
System.out.println(result);
httpClient.getConnectionManager().shutdown();
}
PoolingClientConnectionManager連接池的例程如下:
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
HttpHost googleResearch = new HttpHost("research.google.com", 80);
HttpHost wikipediaEn = new HttpHost("en.wikipedia.org", 80);
cm.setMaxPerRoute(new HttpRoute(googleResearch), 30);
cm.setMaxPerRoute(new HttpRoute(wikipediaEn), 50);
1.首先配置最大連接數和最大路由連接數,如果你要連接的url只有一個,兩個必須配置成一樣,否則只會取最小值。(這是個坑,默認最大連接是20,每個路由最大連接是2)
2.最好配置httpclient連接等待時間,和相應時間。否則就會一直等待。
httpParams = new BasicHttpParams();
httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,CONNECT_TIMEOUT);
httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, READ_TIMEOUT);
3. httpclient必須releaseconnection,但不是abort。因爲releaseconnection是歸還連接到連接池,而abort是直接拋棄這個連接,而且佔用連接池的數目。
HttpGet httpGet = new HttpGet(searchurl);
httpGet.releaseConnection();
4. httpclient設置的最大連接數絕對不能超過tomcat設置的最大連接數,否則tomcat的連接就會被httpclient連接池一直佔用,直到系統掛掉。
5.可以使用tomcat的長連接和htppclient連接池和合理使用來增加系統響應速度。
cm.setMaxTotal(200); //創建socket的上線是200
cm.setDefaultMaxPerRoute(20); //默認對每個指定連接的服務器(指定的ip)可以創建併發20
socket進行訪問
參考:
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e467
http://www.tuicool.com/articles/2eQ7Zj#userconsent#
等等