Android網絡編程-OKHttp源碼角度分析Http

前面介紹了網絡的基礎知識,這篇主要從OKHttp源碼角度來分析Http。OKHttp是一個優秀的網絡請求框架,有以下特點:

  • 支持HTTP2/SPDY
  • Socket自動選擇最好路線,並支持自動重連
  • 擁有自動維護的Socket連接池,減少握手次數
  • 擁有隊列線程池,輕鬆寫併發
  • 擁有Interceptors輕鬆處理請求與響應(比如透明GZIP壓縮)
  • 實現基於Headers的緩存策略

基本使用

同步請求

同步的Get請求

Android網絡編程-OKHttp源碼角度分析Http

異步請求

異步的Get請求

Android網絡編程-OKHttp源碼角度分析Http

源碼分析

我們從OKHttp的初始化開始分析。

OkHttpClient

新建一個OkHttpClient對象

<code>OkHttpClient client = 

new

OkHttpClient();/<code>

構造函數聲明:

Android網絡編程-OKHttp源碼角度分析Http

Builder模式構造:

Android網絡編程-OKHttp源碼角度分析Http

聲明瞭很多屬性,具體含義,等後面用到在具體介紹。

請求流程

請求流程可分為同步和異步,大體的請求流程如下圖所示:

Android網絡編程-OKHttp源碼角度分析Http

OKHttp流程


同步請求流程

<code>

client

.newCall

(

request

)

.execute

();/<code>

newCall返回的是RealCall,上面代碼實際上執行的是RealCall的execute方法。

Android網絡編程-OKHttp源碼角度分析Http

  • executed判斷Call對象是否已經執行,每個Call對象只能執行一次
  • client.dispatcher()返回Dispatcher對象,任務核心調度類,是OKHttp中最重要類之一, executed方法把該線程添加到同步線程隊列synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
  • getResponseWithInterceptorChain()獲取HTTP請求結果,並會進行一系列攔截操作
  • client.dispatcher().finished(this)執行完畢操作
Android網絡編程-OKHttp源碼角度分析Http

執行完畢後,會把線程從同步線程隊列中移除:

Android網絡編程-OKHttp源碼角度分析Http

異步請求流程

RealCall的enqueue方法:

Android網絡編程-OKHttp源碼角度分析Http

  • executed含義和同步請求一樣,表示請求只能執行一次
  • client.dispatcher().enqueue(new AsyncCall(responseCallback));,會生成一個AsyncCall對象,並把它加入到readyAsyncCalls線程隊列中,等待執行

AsyncCall是RealCall的內部類,並且是NamedRunnable線程類,具體執行方法:

Android網絡編程-OKHttp源碼角度分析Http

  • getResponseWithInterceptorChain()獲取HTTP請求結果,並會進行一系列攔截操作
  • client.dispatcher().finished(this);這個方法很重要,和同步方法中調用類似,但是異步的流程則完全不同

finish方法:

Android網絡編程-OKHttp源碼角度分析Http

Android網絡編程-OKHttp源碼角度分析Http

異步流程中,promoteAndExecute方法:

Android網絡編程-OKHttp源碼角度分析Http

會遍歷異步等待線程隊列,並對正在執行的異步線程隊列進行最大請求size,以及每個host最大請求size進行檢查。把異步等待線程放到正在執行線程隊列中,並在等待線程隊列中刪除該線程,這樣就把等待線程變成正在執行線程。

Dispatcher

任務調度核心類,這個類,其實在同步和異步請求流程中已經介紹過,其最重要功能是負責請求的分發。Dispatcher在OKHttpClient的Builder中被初始化:

Android網絡編程-OKHttp源碼角度分析Http

  • maxRequests:最大請求併發請求數64
  • maxRequestsPerHost:每個主機的最大請求數5
  • executorService:線程池
  • readyAsyncCalls:異步等待線程隊列
  • runningAsyncCalls:正在運行的異步線程隊列
  • runningSyncCalls:正在運行的同步線程隊列

線程池executorService的聲明:

Android網絡編程-OKHttp源碼角度分析Http

  • 核心線程數為0,表示線程在空閒時不會被保留,等待一段時間後停止
  • 最大線程數Integer.MAX_VALUE,基本上就是可以創建線程無上限
  • keepAliveTime為60s,表示如果線程空閒時,最多隻能存活60s

綜合上訴,在OKHttp中,設置了不設上限的線程,不保留最小線程,線程空閒時,最大存活時間為60s,保證I/O任務中高阻塞低佔用的過程,不會長時間卡在阻塞上。並通過maxRequests和maxRequestsPerHost來控制併發最大請求數。

攔截器

在同步和異步請求中,具體的執行過程中都會調用到getResponseWithInterceptorChain方法,該方法添加了一系列的攔截器,它在OKHttp整理流程中處於非常重要的地位,

Android網絡編程-OKHttp源碼角度分析Http

流程


方法實現:

Android網絡編程-OKHttp源碼角度分析Http

默認添加的攔截器:

  • RetryAndFollowUpInterceptor:負責失敗重試以及重定向
  • BridgeInterceptor:負責把用戶構造的請求轉換為發送到服務器的請求、把服務器返回的響應轉換為用戶友好的響應
  • CacheInterceptor:負責讀取緩存直接返回、更新緩存
  • ConnectInterceptor:負責和服務器建立連接
  • CallServerInterceptor:負責向服務器發送請求數據、從服務器讀取響應數據

這是典型的責任鏈模式,通過Interceptor,把Request轉換為Response,每個Interceptor都有各自的責任和邏輯。

Android網絡編程-OKHttp源碼角度分析Http

開發者可以自己定義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版本源碼,和以前多版本稍微有些區別。

Android網絡編程-OKHttp源碼角度分析Http

Exchange可以傳輸HTTP請求和響應,並管理連接和事件。newExchange方法調用:

Android網絡編程-OKHttp源碼角度分析Http

find方法會最終執行ExchangeFinder的findConnection方法,在發送HTTP請求之前的邏輯,都是這個方法中實現。

Android網絡編程-OKHttp源碼角度分析Http

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

Android網絡編程-OKHttp源碼角度分析Http

在 for 循環中檢查這個連接是否是隧道協議連接。connectSocket連接socket,establishProtocol根據HTTP協議版本進行連接處理。重點分析下connectSocket方法:

Android網絡編程-OKHttp源碼角度分析Http

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

Android網絡編程-OKHttp源碼角度分析Http

實際執行的方法codec實現類Http1ExchangeCodec(前面根據HTTP協議版本選擇)的writeRequest方法

Android網絡編程-OKHttp源碼角度分析Http

readResponseHeaders

讀取響應頭部,Http1ExchangeCodec的readResponseHeaders方法:

Android網絡編程-OKHttp源碼角度分析Http

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

Android網絡編程-OKHttp源碼角度分析Http

response body

解析 response body 內容:

Android網絡編程-OKHttp源碼角度分析Http

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

Android網絡編程-OKHttp源碼角度分析Http

獲取返回的 body,通過 Source 轉換為需要的數據類型,ResponseBody提供的 string(),轉換為 String 類型

Android網絡編程-OKHttp源碼角度分析Http

通過上述的分析,OKHttp是通過Okio操作Socket實現了Http協議,憑藉高效的性能,Android系統從4.4版本開始,HTTP的實現已經替換為OKHttp。

參考

  • OKHttp源碼解析(一)—初階
  • 拆輪子系列:拆 OkHttp


分享到:


相關文章: