「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
前言
熟悉okhttp要遵循三条主线
- 网络请求如何被封装
- 网络请求如何发发送,发送到哪里
- 网络请求如何被执行
Okhttp 基本实现原理
okhttp框架本质上是用来方便的完成网络请求,为了实现这个目的,它需要处理三件事。
网络请求如何封装
- 通过构建者构建出OkHttpClient对象,再通过newCall方法获得RealCall请求对象
- 网络请求被封装成了RealCall,RealCall通过enqueue加入异步网络请求队列,或者通过execute加入同步网络请求队列。当同一个域名请求数超过5个时,或者超过最大请求数64时,会加入到等待队列。
- RealCall中包含Request是真实的请求参数的封装。
- 在ConnectInterceptor阶段,通过复用connection或者开启新的RealConnection,启动socket链接来发起真实网络请求。
多个网络请求如何处理
dispatcher内部为了三个队列,同步执行队列,异步执行队列,等待队列。以及一个无等待队列的无限大线程池。当有新的请求过来时,判断同一域名请求是否大于5和最大请求数是否大于64,决定加入执行队列或者是等待队列。
网络请求如何被执行
- 构建Request和Call对象
- AsyncCall的Execute为网络请求的入口
- CallServerInterpretor的interpret方法发起真正的网络请求
- 查找或建立socket链接,tls握手过程
- OKio负责读取请求的返回数据
- httpCodec负责解码数据给应用
- 如果是https,还需要完成tls握手过程。
socket如何复用
socket复用的目的
降低请求耗时,同一socket可以减少tcp链接三次握手时间。
复用的条件
tcp四元组相同即可复用,源Ip,源端口,目标ip,目标端口。对于http请求来说,由于都是80端口,因此比对Host即可判定
复用策略
- ConnectionPool中维护了一个双端数组ArrayDeque,保存已经建立的RealConnection。每次新请求到来先判定是否可以复用,如果可以则复用,不可以,则新建RealConnection,并加入到Deque队列末尾。
- ArrayDeque相比LinkedList,区别等同于数组和链表。数组随机访问速度快,遍历速度快,插入和删除速度慢,且需要占据固定大小的连续内存空间。LinkedList插入和删除快,空间分布不连续,随机访问和遍历速度慢。
- connection的链接默认keepAlive的时间是5分钟,超过5分钟或者超过最大的idleConnections(5个)会被常驻的cleanup线程清理掉。清理逻辑为遍历所有的connection如果有被使用的引用计数,则将ideltime设置为当前时间。线程进入休眠。
责任链模式
- 顺序不能变,它代表了网络请求的完整过程。封装请求,缓存处理,socket链接,数据读写,异常处理等。
- 共5级系统拦截器+N个应用自定义的拦截器
- 每个拦截器会加入自己的处理逻辑,并调用下一级的intercept方法。
- 最后一级的intercept方法返回最终的response,并逐级向上返回结果处理。
RetryAndFollowUpInterceptor
重试拦截器,网络请求失败时发起重试。
- socket链接失败
- 请求返回码失败处理。客户端超时,401 407等。
BridgeInterceptor
- 将用户的request添加头信息转化为能够正常的request。如content-type,Content-Length,content-encoding等。
- 添加一些cookie
CacheInterceptor
-
根据http头中的一些信息,比如请求某个资源会返回一个Last-Modified的时间描述,再次请求该资源的时,客户端会添加一个If-Modified-Since,如果时间没有过期,则使用缓存。
-
Last-Modified 与 If-Modified-Since,如果Last-Modified的修改时间早于If-Modified-Since,则该资源的访问返回304.
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
- etag 与 if-None-match,如果tag的key与if-None-match一致,则该资源的访问返回304.
- 底层采用LRUCache作为cache机制。
ConnectInterceptor
实际的tcp链接工作
CallServerInterceptor
发起网络请求,将请求数据写入到socket流中,从socket流中读取数据。底层采用okio来实现。
总结
- okhttp将网络请求封装成call,内部包含用户请求实际内容的Request
- okhttp将请求发送到同步或异步执行队列,在一定条件下会发送到等待队列
- okhttp采用无限多线程的线程池来执行网络请求,该线程池没有等待队列。
- okhttp采用责任链模式来处理网络请求过程的封装,处理过程