1.okhttp3Դ?源码????
2.使用OkHttp发送HTTP请求
3.OkHttp3源码详解之 okhttp连接池复用机制(一)
4.基于OkHttp的Http监控
okhttp3Դ?????
OkHttp是一个相对成熟的解决方案,据说Android4.4的分析源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的源码强大。
OkHttp 处理了很多网络疑难杂症:会从很多常用的分析连接问题中自动恢复。如果您的源码服务器配置了多个IP地址,当第一个IP连接失败的分析docker更新源码时候,OkHttp会自动尝试下一个IP。源码OkHttp还处理了代理服务器问题和SSL握手失败问题。分析
使用 OkHttp 无需重写您程序中的源码网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的分析API。如果你用了 Apache HttpClient,源码则OkHttp也提供了一个对应的分析okhttp-apache 模块。
使用OkHttp发送HTTP请求
OkHttp作为高效且API友好、源码功能丰富的分析HTTP客户端,在Android、源码Kotlin、Java中广泛应用。它提供了一系列特性,包括在连接问题时自动恢复、支持IPv4与IPv6环境下的多活服务、集成TLS功能以及采用链式风格的cbt源码新版Builder设计,支持同步阻塞调用和异步回调调用。
随着OkHttp4.x在年6月发布,其从Java语言转为Kotlin语言,采用Kotlin高效语法,保持了与OkHttp3相同的功能,并通过二进制、Java源码以及Kotlin源码兼容性,确保了升级的平滑过渡。为了升级,开发者可以参考square.github.io/okhttp提供的升级指南。
下面以OkHttp3为例,展示其基本用法。通过OkHttpClient.Builder方法创建实例并设置超时时间,如下:
java
java OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds())
.writeTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(5))
.callTimeout(Duration.ofSeconds())
.build();
可以自定义拦截器以设置特定的Header,例如:
java
public static class DefaultContentTypeInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Content-Type", "application/json")
.build();
return chain.proceed(request);
}
}
或者实现Authenticator接口以添加认证功能:
java
java OkHttpClient okHttpClient = new OkHttpClient.Builder()
.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
if (response.request().header("Authorization") != null) {
return null;
}
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
})
.build();
总结而言,OkHttp提供了丰富的功能,如请求缓存、异步回调等,其简洁的API设计使得HTTP请求的发起与处理变得简单直观,对于开发者来说,redis排序源码不仅能够轻松地封装Request到Response,还能够根据需要自定义拦截器进行额外的设置,满足多样化的网络需求。
OkHttp3源码详解之 okhttp连接池复用机制(一)
提高网络性能优化,关键在于降低延迟和提升响应速度。
在浏览器中发起请求时,header部分通常如下所示:
keep-alive是指浏览器与服务端之间保持长连接,这种连接可以复用。在HTTP1.1中,它默认是开启的。
连接复用为何能提高性能?通常,在发起http请求时,我们需要完成TCP的三次握手、传输数据,最后释放连接。三次握手的过程可以参考这里:TCP三次握手详解及释放连接过程。
一次响应的过程:
在高并发的请求连接情况下或同一客户端多次频繁的请求操作中,无限制地创建连接会导致性能低下。
如果使用keep-alive,在timeout空闲时间内,libevent源码视频连接不会关闭,相同的重复请求将复用原有的connection,减少握手的次数,大幅提高效率。
并非keep-alive的timeout设置时间越长,性能就越好。长时间不关闭会导致过多的僵尸连接和泄露连接出现。
那么,OkHttp3在客户端是如何实现类似keep-alive的机制的?
连接池的类位于okhttp3.ConnectionPool。我们的目标是了解如何在timeout时间内复用connection,并有效地对其进行回收清理操作。
其成员变量代码片段:
excutor:线程池,用于检测闲置socket并进行清理。
connections:connection缓存池。Deque是一个双端列表,支持在头尾插入元素,这里用作LIFO(后进先出)堆栈,多用于缓存数据。
routeDatabase:用于记录连接失败的router。
2.1 缓存操作:
ConnectionPool提供对Deque进行操作的gtest源码解析方法,包括put、get、connectionBecameIdle、evictAll等操作,分别对应放入连接、获取连接、移除连接、移除所有连接操作。
2.2 连接池的清理和回收:
在观察ConnectionPool的成员变量时,我们了解到一个Executor线程池用于清理闲置的连接。注释中这样解释:
Background threads are used to cleanup expired connections
我们在put新连接到队列时,会先执行清理闲置连接的线程。调用的正是executor.execute(cleanupRunnable);方法。观察cleanupRunnable:
线程中不停调用Cleanup清理的动作并立即返回下次清理的间隔时间。继而进入wait等待之后释放锁,继续执行下一次的清理。所以可能理解成它是个监测时间并释放连接的后台线程。
了解cleanup动作的过程。这里就是如何清理所谓闲置连接的流程。怎么找到闲置的连接是主要解决的问题。
在遍历缓存列表的过程中,使用连接数目inUseConnectionCount和闲置连接数目idleConnectionCount的计数累加值都是通过pruneAndGetAllocationCount()是否大于0来控制的。那么很显然,pruneAndGetAllocationCount()方法就是用来识别对应连接是否闲置的。>0则不闲置,否则就是闲置的连接。
进入观察:
好了,原先存放在RealConnection中的allocations派上用场了。遍历StreamAllocation弱引用链表,移除为空的引用,遍历结束后返回链表中弱引用的数量。所以可以看出List>就是一个记录connection活跃情况的List。>0表示活跃,=0表示空闲。StreamAllocation在列表中的数量就是物理socket被引用的次数。
解释:StreamAllocation被高层反复执行aquire与release。这两个函数在执行过程中其实是在一直在改变Connection中的List大小。
搞定了查找闲置的connection操作,我们回到cleanup的操作。计算了inUseConnectionCount和idleConnectionCount之后,程序又根据闲置时间对connection进行了一个选择排序,选择排序的核心是:
通过对比最大闲置时间选择排序可以方便地查找出闲置时间最长的一个connection。如此一来,我们就可以移除这个没用的connection了!
总结:清理闲置连接的核心主要是引用计数器List>和选择排序算法以及excutor的清理线程池。
基于OkHttp的Http监控
在HTTP监控中,关键指标包括入队到请求结束的耗时、DNS查询耗时、socket连接耗时、TLS连接耗时、请求发送耗时、响应传输耗时、首包耗时、响应解析耗时以及HTTP错误,区分业务错误和请求错误。通过可视化工具,可以直观地监控HTTP各阶段的耗时与错误分布,为优化业务HTTP请求提供数据支持。
获取指标数据首先需要定位关键代码,然后插入收集代码。在没有源码或不重新打包源码的情况下,利用实现AOP的工具,通过注解和配置文件在指定函数中插入相关代码。这样可以确保监控代码与业务代码分离。
OkHttp是Android中广泛使用的HTTP请求框架,其最新版本已升级到4.0.x,实现全部由Java替换为Kotlin,API使用也有不同。4.x设备不默认支持TLSV1.2,因此需在API level +和Java 1.8环境下开发,但OkHttp为支持4.x设备单独创建了3..x分支。本文使用的OkHttp版本为3..3。
OkHttp的请求流程如下:首先调用OkHttpClient.Builder设置默认值,然后生成OkHttpClient实例,之后通过OkHttpClient.Builder.build创建RealCall对象。接着,调用RealCall.getResponseWithInterceptorChain方法,再调用RealInterceptorChain.proceed(Request request)发起请求。Interceptor是OkHttp的核心功能类,将网络请求、缓存和压缩等功能统一起来,每个功能都实现为一个Interceptor,形成责任链。关键Interceptor包括ConnectInterceptor和CallServerInterceptor,分别负责连接池管理和与服务器交互。
ConnectInterceptor在连接池中查找可复用连接,若无则创建新socket,进行TLS握手,将socket包装成Okio并创建HttpCodec。CallServerInterceptor使用HttpCodec进行协议传输和解析。
获取指标的实现方式如下:针对HTTP请求耗时、异常、数据大小和状态码,通过MAOP(面向方面编程)拦截OkHttpClient.Builder的build方法加入统计Interceptor和EventListenerFactory。DNS查询耗时、连接耗时、SSL耗时,通过设置EventListener.Factory直接收集。解析耗时需在上层框架如Retrofit的parseReponse方法中收集。首包时间通过拦截读请求数据的方法来实现,即在OkHttp调用CallServerInterceptor时,关注readResponseHeaders的时机。
使用MAOP功能,在AOP配置文件中添加拦截OkHttpClient.Builder的build()方法、Http1Codec的readHeaderLine方法、okhttp3.internal.http2.Http2Stream的takeResponseHeaders方法的配置。首包时间通过拦截方法认为首次返回响应头时计算。对于Retrofit parse耗时收集,需要在AOP配置文件中添加对retrofit2.OKHttp.parseResponse方法的拦截配置,并在Method回调中处理相关数据。
综上所述,该方案能基本实现HTTP基本指标的获取,但在细节上还需完善。欢迎关注知识星球进行深入交流。