编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Android网络编程-OKHttp源码角度分析Http

wxchong 2024-06-10 17:04:17 开源技术 21 ℃ 0 评论

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

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

基本使用

同步请求

同步的Get请求

异步请求

异步的Get请求

源码分析

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

OkHttpClient

新建一个OkHttpClient对象

OkHttpClient client = new OkHttpClient();

构造函数声明:

Builder模式构造:

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

请求流程

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

OKHttp流程


同步请求流程

client.newCall(request).execute();

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

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

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

异步请求流程

RealCall的enqueue方法:

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

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

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

finish方法:

异步流程中,promoteAndExecute方法:

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

Dispatcher

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

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

线程池executorService的声明:

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

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

拦截器

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

流程


方法实现:

默认添加的拦截器:

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

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

开发者可以自己定义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版本源码,和以前多版本稍微有些区别。

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

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

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

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

使用 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方法

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

readResponseHeaders

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

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

response body

解析 response body 内容:

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

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

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

参考

  • OKHttp源码解析(一)—初阶
  • 拆轮子系列:拆 OkHttp

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表