httpclient 優化


 (1)采用單例模式(重用HttpClient實例)
    對於一個通信單元甚至是整個應用程序,Apache強烈推薦只使用一個HttpClient的實例。例如:

    private static HttpClient httpClient = null;
 
    private static synchronized HttpClient getHttpClient() {
       if(httpClient == null) {
           final HttpParams httpParams = new BasicHttpParams();  
           httpClient = new DefaultHttpClient(httpParams); 
       }  
  
      return httpClient;
    }

    (2)保持連接(重用連接)
    對於已經和服務端建立了連接的應用來說,再次調用HttpClient進行網絡數據傳輸時,就不必重新建立新連接了,而可以重用已經建立的連接。這樣無疑可以減少開銷,提升速度。
    在這個方面,Apache已經做了“連接管理”,默認情況下,就會盡可能的重用已有連接,因此,不需要客戶端程序員做任何配置。只是需要注意,Apache的連接管理並不會主動釋放建立的連接,需要程序員在不用的時候手動關閉連接。

    (3)多線程安全管理的配置
    如果應用程序采用了多線程進行網絡訪問,則應該使用Apache封裝好的線程安全管理類ThreadSafeClientConnManager來進行管理,這樣能夠更有效且更安全的管理多線程和連接池中的連接。
    (在網上也看到有人用MultiThreadedHttpConnectionManager進行線程安全管理的,后查了下Apache的API,發現MultiThreadedHttpConnectionManager是API 2.0中的類,而ThreadSafeClientConnManager是API 4.0中的類,比前者更新,所以選擇使用ThreadSafeClientConnManager。另外,還看到有PoolingClientConnectionManager這個類,是API 4.2中的類,比ThreadSafeClientConnManager更新,但Android SDK中找不到該類。所以目前還是選擇了ThreadSafeClientConnManager進行管理)
    例如:

    ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry); 
    httpClient = new DefaultHttpClient(manager, httpParams);

    (4)大量傳輸數據時,使用“請求流/響應流”的方式
    當需要傳輸大量數據時,不應使用字符串(strings)或者字節數組(byte arrays),因為它們會將數據緩存至內存。當數據過多,尤其在多線程情況下,很容易造成內存溢出(out of memory,OOM)。
    而HttpClient能夠有效處理“實體流(stream)”。這些“流”不會緩存至內存、而會直接進行數據傳輸。采用“請求流/響應流”的方式進行傳輸,可以減少內存占用,降低內存溢出的風險。
    例如:

    // Get method: getResponseBodyAsStream()
    // not use getResponseBody(), or getResponseBodyAsString()
    GetMethod httpGet = new GetMethod(url);  
    InputStream inputStream = httpGet.getResponseBodyAsStream();

    // Post method: getResponseBodyAsStream()
    PostMethod httpPost = new PostMethod(url);  
    InputStream inputStream = httpPost.getResponseBodyAsStream(); 

    (5)持續握手(Expect-continue handshake)
    在認證系統或其他可能遭到服務器拒絕應答的情況下(如:登陸失敗),如果發送整個請求體,則會大大降低效率。此時,可以先發送部分請求(如:只發送請求頭)進行試探,如果服務器願意接收,則繼續發送請求體。此項優化主要進行以下配置:

    // use expect-continue handshake
    HttpProtocolParams.setUseExpectContinue(httpParams, true);

    (6)“舊連接”檢查(Stale connection check)
    HttpClient為了提升性能,默認采用了“重用連接”機制,即在有傳輸數據需求時,會首先檢查連接池中是否有可供重用的連接,如果有,則會重用連接。同時,為了確保該“被重用”的連接確實有效,會在重用之前對其進行有效性檢查。這個檢查大概會花費15-30毫秒。關閉該檢查舉措,會稍微提升傳輸速度,但也可能出現“舊連接”過久而被服務器端關閉、從而出現I/O異常。
    關閉舊連接檢查的配置為:
    // disable stale check
    HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);

    (7)超時設置
    進行超時設置,讓連接在超過時間后自動失效,釋放占用資源。
    // timeout: get connections from connection pool
    ConnManagerParams.setTimeout(httpParams, 1000);  
    // timeout: connect to the server
    HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
    // timeout: transfer data from server
    HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);

在Apache的HttpClient包中,有三個設置超時的地方:

/ 從連接池中取連接的超時時間/

ConnManagerParams.setTimeout(params, 1000);

/連接超時/

HttpConnectionParams.setConnectionTimeout(params, 2000);

/請求超時/

HttpConnectionParams.setSoTimeout(params, 4000);

第一行設置ConnectionPoolTimeout:

這定義了從ConnectionManager管理的連接池中取出連接的超時時間,此處設置為1秒。

第二行設置ConnectionTimeout:

這定義了通過網絡與服務器建立連接的超時時間。Httpclient包中通過一個異步線程去創建與服務器的socket連接,這就是該socket連接的超時時間,此處設置為2秒。

第三行設置SocketTimeout:

這定義了Socket讀數據的超時時間,即從服務器獲取響應數據需要等待的時間,此處設置為4秒。

connectionTimeout:指的是連接一個url的連接等待時間。

soTimeout:指的是連接上一個url,獲取response的返回等待時間


    (8)連接數限制
    配置每台主機最多連接數和連接池中的最多連接總數,對連接數量進行限制。其中,DEFAULT_HOST_CONNECTIONS和DEFAULT_MAX_CONNECTIONS是由客戶端程序員根據需要而設置的。
    // set max connections per host
    ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS)); 
    // set max total connections
    ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);




   
   
   
           
  1. private static synchronized HttpClient getHttpClient() {
  2. if(httpClient == null) {
  3. final HttpParams httpParams = new BasicHttpParams();
  4. // timeout: get connections from connection pool
  5. ConnManagerParams.setTimeout(httpParams, 1000);
  6. // timeout: connect to the server
  7. HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
  8. // timeout: transfer data from server
  9. HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
  10. // set max connections per host
  11. ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));
  12. // set max total connections
  13. ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
  14. // use expect-continue handshake
  15. HttpProtocolParams.setUseExpectContinue(httpParams, true);
  16. // disable stale check
  17. HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
  18. HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
  19. HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
  20. HttpClientParams.setRedirecting(httpParams, false);
  21. // set user agent
  22. String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
  23. HttpProtocolParams.setUserAgent(httpParams, userAgent);
  24. // disable Nagle algorithm
  25. HttpConnectionParams.setTcpNoDelay(httpParams, true);
  26. HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
  27. // scheme: http and https
  28. SchemeRegistry schemeRegistry = new SchemeRegistry();
  29. schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
  30. schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
  31. ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
  32. httpClient = new DefaultHttpClient(manager, httpParams);
  33. }
  34. return httpClient;
  35. }




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM