android 闹钟源码分析_Android网络编程-OKHttp源码角度分析Http

前面介绍了网络的基础知识,这篇主要从OKHttp源码角度来分析Http。OKHttp是一个优秀的网络请求框架,有以下特点:

  • 支持HTTP2/SPDY
  • Socket自动选择最好路线,并支持自动重连
  • 拥有自动维护的Socket连接池,减少握手次数
  • 拥有队列线程池,轻松写并发
  • 拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩)
  • 实现基于Headers的缓存策略

基本使用

同步请求

同步的Get请求

76c86eb8a7b4f4ae2395c65a16326c57.png

异步请求

异步的Get请求

32985450c0105b768bc2487b4844c271.png

源码分析

我们从OKHttp的初始化开始分析。

OkHttpClient

新建一个OkHttpClient对象

OkHttpClient client = new OkHttpClient();

构造函数声明:

e4379adaaf818b41830e70654f8b87c1.png

Builder模式构造:

f6a6dd3155f4315ce03c5d7b8fd6e30a.png

声明了很多属性,具体含义,等后面用到在具体介绍。

请求流程

请求流程可分为同步和异步,大体的请求流程如下图所示:

5ae480b5e9ee89c7c4cbf1646c1c595b.png

OKHttp流程

同步请求流程

client.newCall(request).execute();

newCall返回的是RealCall,上面代码实际上执行的是RealCall的execute方法。

decd3699de4191cebaa55cc0a9c1e9ec.png
  • executed判断Call对象是否已经执行,每个Call对象只能执行一次
  • client.dispatcher()返回Dispatcher对象,任务核心调度类,是OKHttp中最重要类之一, executed方法把该线程添加到同步线程队列synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
  • getResponseWithInterceptorChain()获取HTTP请求结果,并会进行一系列拦截操作
  • client.dispatcher().finished(this)执行完毕操作
729722c40cc435ac2b7c27f5540595b9.png

执行完毕后,会把线程从同步线程队列中移除:

0d3d7f8e5592689c3b998f30e3937976.png

异步请求流程

RealCall的enqueue方法:

b72844d4b66c0ea2445e66c159ae15d7.png
  • executed含义和同步请求一样,表示请求只能执行一次
  • client.dispatcher().enqueue(new AsyncCall(responseCallback));,会生成一个AsyncCall对象,并把它加入到readyAsyncCalls线程队列中,等待执行

AsyncCall是RealCall的内部类,并且是NamedRunnable线程类,具体执行方法:

82595b3f89298631a4bbe9ee6c3730be.png
  • getResponseWithInterceptorChain()获取HTTP请求结果,并会进行一系列拦截操作
  • client.dispatcher().finished(this);这个方法很重要,和同步方法中调用类似,但是异步的流程则完全不同

finish方法:

f0b366ba2fd71ec06f18a54cb85dacea.png
545203a0f6044e4b7ec681df607844a9.png

异步流程中,promoteAndExecute方法:

d95a4c54ae576e2c34feda453805a3eb.png

会遍历异步等待线程队列,并对正在执行的异步线程队列进行最大请求size,以及每个host最大请求size进行检查。把异步等待线程放到正在执行线程队列中,并在等待线程队列中删除该线程,这样就把等待线程变成正在执行线程。

Dispatcher

任务调度核心类,这个类,其实在同步和异步请求流程中已经介绍过,其最重要功能是负责请求的分发。Dispatcher在OKHttpClient的Builder中被初始化:

14873b241030fe52b104beb35b10ef90.png
  • maxRequests:最大请求并发请求数64
  • maxRequestsPerHost:每个主机的最大请求数5
  • executorService:线程池
  • readyAsyncCalls:异步等待线程队列
  • runningAsyncCalls:正在运行的异步线程队列
  • runningSyncCalls:正在运行的同步线程队列

线程池executorService的声明:

f57c8b9f497beb1e44c088006c8fdb2e.png
  • 核心线程数为0,表示线程在空闲时不会被保留,等待一段时间后停止
  • 最大线程数Integer.MAX_VALUE,基本上就是可以创建线程无上限
  • keepAliveTime为60s,表示如果线程空闲时,最多只能存活60s

综合上诉,在OKHttp中,设置了不设上限的线程,不保留最小线程,线程空闲时,最大存活时间为60s,保证I/O任务中高阻塞低占用的过程,不会长时间卡在阻塞上。并通过maxRequests和maxRequestsPerHost来控制并发最大请求数。

拦截器

在同步和异步请求中,具体的执行过程中都会调用到getResponseWithInterceptorChain方法,该方法添加了一系列的拦截器,它在OKHttp整理流程中处于非常重要的地位,

2c329a4c3d1638a4ca08929d95ef7c9f.png

流程

方法实现:

16dba29982db94c110d600f0028a7734.png

默认添加的拦截器:

  • RetryAndFollowUpInterceptor:负责失败重试以及重定向
  • BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应
  • CacheInterceptor:负责读取缓存直接返回、更新缓存
  • ConnectInterceptor:负责和服务器建立连接
  • CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据

这是典型的责任链模式,通过Interceptor,把Request转换为Response,每个Interceptor都有各自的责任和逻辑。

cd69a7aae0a1fdf95c8b9343c3e1319d.png

开发者可以自己定义Interceptor,在最开始或者发送请求前,对Request和Response进行处理。

HTTP实现

OKHttp中实现HTTP主要是在ConnectInterceptor和CallServerInterceptor。ConnectInterceptor建立服务器之间的连接,CallServerInterceptor发送请求和读取响应。OKHttp请求一个URL的流程:

根据请求的URL,createAddress方法会创建一个Address,用于连接服务器检查address和routes,是否可以从ConnectionPool获取一个连接如果没有获取到连接,会进行下一个路由选择(routeSelector),并且重新尝试从ConnectionPool获取一个连接。重试还是获取不到,就会重新创建一个连接(RealConnection)获取连接后,它会与服务器建立一个直接的Socket连接、使用TLS安全通道(基于HTTP代理的HTTPS),或直接TLS连接发送HTTP请求,并获取响应

ConnectInterceptor

在请求发送前的逻辑,都是ConnectInterceptor中实现,ConnectInterceptor的intercept,这个是3.14.2版本源码,和以前多版本稍微有些区别。

344b41a36789789b008fbfaeb8540266.png

Exchange可以传输HTTP请求和响应,并管理连接和事件。newExchange方法调用:

d76e878458d68fa6d9442338fe5bc628.png

find方法会最终执行ExchangeFinder的findConnection方法,在发送HTTP请求之前的逻辑,都是这个方法中实现。

c45bb254a59ade5869822a110d6d7c3a.png

HTTP 的连接主要是result.connect方法:

64e5bf7b2fbf80911de65bac3f818087.png

在 for 循环中检查这个连接是否是隧道协议连接。connectSocket连接socket,establishProtocol根据HTTP协议版本进行连接处理。重点分析下connectSocket方法:

62954ad63d421aea4cca4f7b08cc4e5b.png

使用 Okio,封装了Socket的读写操作, 建立连接后,就可以发送请求和获取响应。

CallServerInterceptor

CallServerInterceptor的intercept()方法里负责发送请求和获取响应。具体操作都是通过Exchange来执行,Exchange通过各个功能模块再进行分发处理。通过 Socket 发送 HTTP消息,会按照以下声明周期:

  • writeRequestHeaders发送 request Headers
  • 如果有 request body,就通过 Sink 发送request body,然后关闭 Sink
  • readResponseHeaders获取 response Headers
  • 通过Source读取 response body,然后关闭 Source
writeRequestHeaders

Exchange 调用writeRequestHeaders方法

3f6560abf1b4fcf035d514db6f94842c.png

实际执行的方法codec实现类Http1ExchangeCodec(前面根据HTTP协议版本选择)的writeRequest方法

90810d03d28787034a44d820a29d542a.png
readResponseHeaders

读取响应头部,Http1ExchangeCodec的readResponseHeaders方法:

26f0a68512cef75ec62e1bf3b2d4a9bc.png

StatusLine解析HTTP版本信息,readHeaders()读取response header 信息。

85f8fb176aca08d3b79d011ab6f3fdfc.png
response body

解析 response body 内容:

1909a4391babcd485c51360e25b71122.png

如果不是websocket,调用Exchange的openResponseBody方法:

c7a79a2e45d833e1bd07a9a41ad643ad.png

获取返回的 body,通过 Source 转换为需要的数据类型,ResponseBody提供的 string(),转换为 String 类型

c2f31fe484f25d6d4f3a01520140710c.png

通过上述的分析,OKHttp是通过Okio操作Socket实现了Http协议,凭借高效的性能,Android系统从4.4版本开始,HTTP的实现已经替换为OKHttp。

参考

  • OKHttp源码解析(一)—初阶
  • 拆轮子系列:拆 OkHttp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值