首先,HttpClient可以共用,减少创建HttpClient的开销。当然,如果你的应用调用HttpClient并不怎么频繁的话那就没必要共用了,毕竟在内存中维护一个空闲的httpClient对象是不保险的。
其次,Connection可以重用,减少建立连接的开销。
要完成以上两点,可以用多线程下的MultiThreadedHttpConnectionManager管理HttpConnection和HttpClient。MultiThreadedHttpConnectionManager管理的HttpClient是线程安全的,可以做成单例的。但是值得注意的是每个线程应该有自己的HttpMethod和HttpState、HttpConfiguration,以区分每次请求的host和HttpSession 。如下所示:
private static MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager(); private HttpClient client = new HttpClient(httpConnectionManager);
定义好后,在静态块中初始化相关参数
static { //每主机最大连接数和总共最大连接数,通过hosfConfiguration设置host来区分每个主机 client.getHttpConnectionManager().getParams().setDefaultMaxConnectionsPerHost(8); client.getHttpConnectionManager().getParams().setMaxTotalConnections(48); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); client.getHttpConnectionManager().getParams().setSoTimeout(5000); client.getHttpConnectionManager().getParams().setTcpNoDelay(true); client.getHttpConnectionManager().getParams().setLinger(1000); //失败的情况下会进行3次尝试,成功之后不会再尝试 client.getHttpConnectionManager().getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); }
HttpConfiguration中有一些参数对提高性能有一些帮助,主要说明如下:
DefaultMaxConnectionsPerHost参数定义每台主机允许的最大连接数,默认为2。这个参数只能用于一些特定的httpConnectionManager,比如MultiThreadedHttpConnectionManager。
MaxTotalConnections参数表示httpConnectionManager管理的最大连接数,默认为20。同上个参数,这个参数也只是在某些特定的httpConnectionManager中有用。
setTcpNoDelay(true)设置是否启用Nagle算法,设置true后禁用Nagle算法,默认为false(即默认启用Nagle算法)。Nagle算法试图通过减少分片的数量来节省带宽。当应用程序希望降低网络延迟并提高性能时,它们可以关闭Nagle算法,这样数据将会更早地发送,但是增加了网络消耗。
setLinger(1000)设置socket延迟关闭时间,值为0表示这个选项是关闭的,值为-1表示使用JRE的默认设置。
setStaleCheckingEnabled(true)参数设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间[3]。
然后,在每个线程代码中,创建自己的HttpMethod。
还有一个很重要的优化点是采用请求/响应实体流,尤其是在请求频繁数据量大的情况下,很大的实体不会被缓存在内存中而直接发送或接收,采用流能有效的提高性能。虽然这些实体可以是字符串或者字节数组,但是它们容易导致内存泄露,你得小心的使用他们,因为它们是整个实体缓存在内存中的。
对于响应流,采用method的getResponseBodyAsStream()来代替getResponseBody() 和getResponseBodyAsString().如下所示:
HttpClient httpclient = new HttpClient(); GetMethod httpget = new GetMethod("http://www.myhost.com/"); try { httpclient.executeMethod(httpget); Reader reader = new InputStreamReader(httpget.getResponseBodyAsStream(), httpget.getResponseCharSet()); // consume the response entity } finally { httpget.releaseConnection(); }
而对于请求流,可以通过实现RequestEntity自定义自己的各种流,httpclient包含了常见的几种实现,如FileRequestEntity、ByteArrayRequestEntity、StringRequestEntity、MultipartRequestEntity等。使用示例如下:
File myfile = new File("myfile.txt"); PostMethod httppost = new PostMethod("/stuff"); httppost.setRequestEntity(new FileRequestEntity(myfile));
如果客户端和服务器的通讯不需要保持会话状态的话,可以通过禁用Cookie来提高一点点性能,比如蜘蛛爬虫之类应用。如下:
HttpMethod method = new GetMethod(); method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); method.setRequestHeader("Cookie", "special-cookie=value");
参考资料:
1. http://hc.apache.org/httpclient-3.x/performance.html
(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()方法代码如下:
- private static synchronized HttpClient getHttpClient() {
- if(httpClient == null) {
- final HttpParams httpParams = new BasicHttpParams();
- // 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);
- // set max connections per host
- ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS));
- // set max total connections
- ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
- // use expect-continue handshake
- HttpProtocolParams.setUseExpectContinue(httpParams, true);
- // disable stale check
- HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
- HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
- HttpClientParams.setRedirecting(httpParams, false);
- // set user agent
- String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
- HttpProtocolParams.setUserAgent(httpParams, userAgent);
- // disable Nagle algorithm
- HttpConnectionParams.setTcpNoDelay(httpParams, true);
- HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
- // scheme: http and https
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
- ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
- httpClient = new DefaultHttpClient(manager, httpParams);
- }
- return httpClient;
- }
附录:关于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连接,以优化性能和资源利用。 然而,需要注意的是,虽然HttpClient 3.x系列是一个成熟且广泛使用的库,但它已不再维护,最新的版本是4.x系列。对于新的项目,推荐使用Apache ...
总之,Android Asynchronous HTTPClient是实现异步网络请求的一种有效工具,但在实际项目中,开发者应根据需求选择最合适的网络库,并结合各种优化策略,确保应用的性能和用户体验。随着技术的发展,不断学习和尝试...
标题中的"org.apache.commons.httpclient相关架包"指的是这个库的一系列组件,主要包含在`httpclient.jar`文件中。这个JAR文件包含了HttpClient库的所有必需类和资源,可以被导入到Java项目中以实现HTTP通信功能。 ...
10. **性能优化**:通过配置连接超时、响应超时、线程池大小等参数,以及使用合适的连接管理策略,可以进一步优化HttpClient的性能。 在实际使用HttpClient时,需要根据项目需求选择合适的版本,理解其工作原理,...
可以通过设置连接超时、读写超时、最大连接数、连接复用策略等来优化HttpClient的性能。 10. **异步操作**: HttpClient也支持异步操作,通过`HttpAsyncClient`类,可以在回调函数中处理响应,适合于高并发场景。...
综上所述,升级到HttpComponents HttpClient 4.x是一个复杂的过程,涉及到对新API的深入学习,理解新的编程模型和网络编程的优化。升级的好处包括性能的提升、更好的错误处理机制以及对最新HTTP协议特性的支持。通过...
在标题"org.apache.commons.httpclient相关资源包"中,我们可以看出这是关于使用Apache HttpClient进行HTTP通信的知识点。Apache HttpClient库是Apache软件基金会的一个项目,它提供了对HTTP协议的全面支持,包括GET...
HttpClient 4.2.1是这个库的一个稳定版本,提供了丰富的功能和优化,使得开发者能够高效、可靠地执行HTTP操作。本文将深入探讨HttpClient 4.2.1的核心特性和使用方法,帮助开发者更好地理解和应用这个强大的工具。 ...
《HttpClient 4.2.2及其相关库的深度解析》 HttpClient是Apache软件基金会开发的一个Java库,专门用于执行HTTP请求。在标题提及的“httpclient 4.2.2”版本中,HttpClient提供了一个强大且灵活的工具集,允许开发者...
HttpClient 4.4.1是HttpClient系列的一个稳定版本,它主要关注性能优化和错误修复。以下是一些关键特性: - **连接管理**:HttpClient 4.4.1引入了更智能的连接管理和重用策略,提高了并发性能。它支持多路复用,...
文件名为httpClient的压缩包很可能包含了封装HttpClient的相关代码,可能包括配置类、请求执行类、异常处理类等。解压并研究这些文件,可以帮助我们理解具体是如何进行封装的,也可以为我们的项目提供参考和学习的...
4. **性能优化**:合理配置连接池大小、超时时间、重试策略等参数,可以显著提升HttpClient的性能。 5. **线程安全**:HttpClient实例不是线程安全的,如果在多线程环境中使用,需要为每个线程创建独立的HttpClient...
HttpClient是Apache软件基金会的一个开源Java库,用于执行HTTP请求。...HttpClient支持各种HTTP方法(如GET、POST、PUT、DELETE等),...在使用过程中,注意根据项目需求进行适当的配置和优化,以确保最佳的性能和可靠性。
HttpClient 4.1.2是Apache HttpClient的一个稳定版本,它在前一版本的基础上进行了优化和增强,为开发者提供了更加高效、可靠的网络请求处理能力。 HttpClient 4.1.2的核心在于其对HTTP协议的全面支持,包括基本的...
你可以通过设置最大连接数、每个路由的最大连接数等参数来优化连接管理。 2. **请求执行器(RequestExecutor)**:HttpClient 4.3允许自定义请求执行策略,比如同步或异步执行。`HttpRequestExecutor`是默认的执行...
虽然`commons-httpclient-3.0.jar`是一个经典版本,但随着Java的发展,Apache社区已经推出了更现代的HttpClient 4.x系列,提供了更多改进和优化,如更好的线程安全、更丰富的API以及对HTTP/2的支持。因此,建议在新...
- 在Android开发中,HttpClient也可通过`AndroidHttpClient`类进行优化,以适应移动设备的特性。 总的来说,HttpClient 4.5.3是Java开发者进行网络通信的强大工具,它提供了丰富的功能和高度的灵活性。通过深入...
HttpClient是Apache基金会开发的一个Java库,它为Java开发者提供了一种简单且强大的API来执行HTTP请求,无论是GET、POST还是...无论你是新手还是经验丰富的开发者,HttpClient都能帮助你更高效地完成HTTP相关的任务。
10. **性能优化**: - 使用预连接(pre-emptive authentication)和连接池来减少延迟,提高响应速度。 - 使用压缩算法(如gzip)减小传输的数据量。 在实际应用中,开发者可以根据具体需求对HttpClient进行细致的...
封装后,我们可以控制实例的生命周期,或者使用`HttpClientFactory`来创建和管理实例,以优化连接池的使用。 2. **请求和响应的缓存**:为了提高性能,我们可以添加缓存机制,对于某些不变的HTTP请求,可以直接返回...