HttpClient 网络优化

尽管Android官网推荐在2.3及后续版本中使用HttpURLConnection作为网络开发首选类,但在连接管理和线程安全方面,HttpClient还是具有很大优势。就目前而言,HttpClient仍是一个值得考虑的选择。对于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);

(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);

经过优化后,上一篇日志中的getHttpClient()方法代码如下:

  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. }

附录:关于HttpURLConnection的优化,网上资料不多。从Android官网上看到一点,整理如下:

(1)上传数据至服务器时(即:向服务器发送请求),如果知道上传数据的大小,应该显式使用
setFixedLengthStreamingMode(int)来设置上传数据的精确值;如果不知道上传数据的大小,则应使用
setChunkedStreamingMode(int)——通常使用默认值“0”作为实际参数传入。如果两个函数都未设置,则系统会强制将“请求体”
中的所有内容都缓存至内存中(在通过网络进行传输之前),这样会浪费“堆”内存(甚至可能耗尽),并加重隐患。

(2)如果通过流(stream)输入或输出少量数据,则需要使用带缓冲区的流(如BufferedInputStream);大量读取或输出数据时,可忽略缓冲流(不使用缓冲流会增加磁盘I/O,默认的流操作是直接进行磁盘I/O的);

(3)当需要传输(输入或输出)大量数据时,使用“流”来限制内存中的数据量——即:将数据直接放在“流”中,而不是存储在字节数组或字符串中(这些都存储在内存中)。

参考文章:

http://hc.apache.org/httpclient-3.x/performance.html

http://blog.csdn.net/androidzhaoxiaogang/article/details/8198400

http://guowww.diandian.com/post/2011-11-07/15351973

http://blog.csdn.net/ken831001/article/details/7925309

http://www.iteye.com/topic/1117362

http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html

http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html

HttpClient 网络优化的更多相关文章

  1. Android4种网络连接方式HttpClient、HttpURLConnection、OKHttp和Volley优缺点和性能对比

    比较的指标: 1.cpu 2.流量 3.电量 4.内存占用 5.联网时间 功能点: 1.重试机制 2.提供的扩展功能 3.易用性 4.是否https 5.是否支持reflect api,OkHttp有 ...

  2. Android移动端网络优化

    介绍下针对移动端的网络优化,不限于 Android,同样适用于 iOS 和 H5 本文为性能优化系列第四篇,目前性能调优专题已完成以下部分: 性能优化总纲——性能问题及性能调优方式 性能优化第四篇—— ...

  3. HttpClient的替代者 - RestTemplate

    需要的包 ,除了Spring的基础包外还用到json的包,这里的数据传输使用json格式 客户端和服务端都用到一下的包 <!-- Spring --> <dependency> ...

  4. 关于微软HttpClient使用,避免踩坑

    最近公司对于WebApi的场景使用也越来越加大了,随之而来就是Api的客户端工具我们使用哪个?我们最常用的估计就是HttpClient,在微软类库中命名空间地址:System.Net.Http,是一个 ...

  5. 使用HttpClient的优解

    新工作入职不满半周,目前仍然还在交接工作,适应环境当中,笔者不得不说看别人的源码实在是令人痛苦.所幸今天终于将大部分工作流畅地看了一遍,接下来就是熟悉框架技术的阶段了. 也正是在看源码的过程当中,有一 ...

  6. Java的异步HttpClient

    上篇提到了高性能处理的关键是异步,而我们当中许多人依旧在使用同步模式的HttpClient访问第三方Web资源,我认为原因之一是:异步的HttpClient诞生较晚,许多人不知道:另外也可能是大多数W ...

  7. 揭秘Windows10 UWP中的httpclient接口[2]

    阅读目录: 概述 如何选择 System.Net.Http Windows.Web.Http HTTP的常用功能 修改http头部 设置超时 使用身份验证凭据 使用客户端证书 cookie处理 概述 ...

  8. C#中HttpClient使用注意:预热与长连接

    最近在测试一个第三方API,准备集成在我们的网站应用中.API的调用使用的是.NET中的HttpClient,由于这个API会在关键业务中用到,对调用API的整体响应速度有严格要求,所以对HttpCl ...

  9. HttpClient调用webApi时注意的小问题

    HttpClient client = new HttpClient(); client.BaseAddress = new Uri(thisUrl); client.GetAsync("a ...

随机推荐

  1. 【linux】常用网站

    Kernel: http://www.kernel.org/ LSB (Linux Standard Base): http://www.linuxbase.org/ ELC(Embedded Lin ...

  2. Qt学习经验之quit()、exit()、close()《转载》

       使用QT编辑界面,其中带来很大方便的一点就是Qt中自带丰富的.种类齐全的类及其功能函数,程序员可以在编辑程序的过程中简单地直接调用.关于窗口关闭的操作,在这里指出常用的三个槽,即quit(),e ...

  3. Servlet过滤器——过滤器分析流量

    1.概述 Servlet过滤器可以对用户提交的数据或服务器返回的数据进行更改.任何到达服务器的请求都会首先经过过滤器的处理.本实例应用过滤器的这个特点,编写了一个在过滤器中统计网站流量的实例. 本实例 ...

  4. javascript中apply和eval结合的强大用法

        eval是一个函数,可以接受一个参数,这个参数可以作为js语句被解释性的执行,利用这个特性,eval和apply结合起来,可以大大简化代码  如下例子 <a class="cl ...

  5. cpp check 分析

    1 FileTabCharacterCheck 为什么检查: 因为对于一个TAB而言,所空的空格不定是固定的,如果在机器A上设置了是4个空格,显示正常,而在机器B上阅读,B机器是100个空格为一个TA ...

  6. unity3d ngui-TweenRotation-TweenPosition-TweenScale

    using UnityEngine; using System.Collections; public class TweenFlipCARDS : MonoBehaviour { private f ...

  7. Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统(转)

    Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统! Tair专为小文件优化,并提供简单易用的接口(类似Map)Tair支持Java和C版本的客户端 Tair is a di ...

  8. 设定十分钟android在状态栏上集成的开源project推荐

    1.前言 于android kitkat 有一个新功能可以设置背景的手机状态栏,让手机风的整个界面格是一致的,它看起来非常酷,在今年的google i/o向上android l这样的风格.来如今看我们 ...

  9. cocos2dx--两个场景切换各函数调用顺序

    场景A切换到场景B,有切换特效 调用顺序例如以下:(AAABABABA) A:构造函数 A:onEnter A:onEnterTransitionDidFinish B:构造函数 A:onExitTr ...

  10. js错误 SyntaxError: missing : after property id

    在用jquery的post方法时 $.post('adminCheckTpmisPlans.do',{'test',str},function(f){ ... }) 报如下错误 SyntaxError ...