圖文詳解OkHttp的超時時間

前言

雖然網上有很多關於okhttp超時時間的文章但大多都一筆帶過並沒有進行詳細的講解各自的作用,於是就看瞭下源碼大致寫一下其中的發現.

本文以 ‘com.squareup.okhttp3:okhttp:3.12.0’源碼為參考

首先我們一共可以設置5個超時時間分別如下:

OkHttpClient client = new OkHttpClient.Builder()

.connectTimeout(30, TimeUnit.SECONDS)

.callTimeout(120, TimeUnit.SECONDS)

.pingInterval(5, TimeUnit.SECONDS)

.readTimeout(60, TimeUnit.SECONDS)

.writeTimeout(60, TimeUnit.SECONDS)

.build();

其中callTimeout,readTimeout,writeTimeout和okio的AsyncTimeout有著密不可分的關系,其內部維護瞭一個Watchdog,單獨開一個線程死循環判斷是否超時

connectTimeout:

指的是建立連接所用的時間,適用於網絡狀況正常的情況下,兩端連接所用的時間。

通過跟源碼發現這個值用在瞭 socket.connect(address, connectTimeout);

callTimeout:

這個值從調用call.execute();和enqueue();這兩個方法開始計時,時間到後網絡還未請求完成將調用cancel();方法
在RealCall類中可以看到在構造方法中創建timeout匿名內部類

在execute方法中開始計時

在timeoutExit方法中結束計時

pingInterval

通過跟源碼我們可以看到,這個值隻有http2和webSocket中有使用

如果設置瞭這個值會定時的向服務器發送一個消息來保持長連接

所以在寫websocket時是完全可以隻用設置這個值來保持長連接的.

客戶端在發送ping消息時服務端會相應的返回pong消息來進行回應.同時okhttp也實現瞭pong,服務端在發起ping的時候客戶端會通過pong來進行回應,即:在進行長連接時,客戶端不需要進行隻需要服務端進行定時ping也是可以保持長連接的.

接下來就開始講和我們密切相關的readTimeout和writeTimeout瞭,當然也是最復雜的.其中最重要的還是readTimeout,我們先看writeTimeout

writeTimeout

這個值大致有3個地方用到

其中第二處和第三處的用用法是一致的,最後都是調用瞭

sink.timeout().timeout(writeTimeout, MILLISECONDS);

這寫到底是什麼意思呢?

這個就不得不說okio瞭,okhttp中幾乎所有的流的操作都是由okio完成的,在okio.AsyncTimeout中對Sink(類似於OutputStream)和Source(類似於InputStream)進行瞭一層封裝

/**

Don’t write more than 64 KiB of data at a time, give or take a segment. Otherwise slow
connections may suffer timeouts even when they’re making (slow) progress. Without this, writing
a single 1 MiB buffer may never succeed on a sufficiently slow connection.
*/
private static final int TIMEOUT_WRITE_SIZE = 64 * 1024;

這其中的邏輯還是相當復雜的,大致意思就是所有的sink都被封裝瞭一個超時機制,需要在我們設置的時間內寫出TIMEOUT_WRITE_SIZE(64k)的數據,如果無法完成即為超時,所以,我們在上次文件時明明隻設置瞭幾十秒的超時時間卻不會超時.

在http2中就沒有再使用okio的超時機制瞭,當然超時計時器還是用的AsyncTimeout.的Watchdog




可以看到,在http2中采用的是線程等待的策略

readTimeout

readTimeout和writeTimeout幾乎完全一樣,隻是操作相反,而且header的讀取和body的讀取是分開進行的,由於header數據量較小就不用討論瞭.

okio中每次讀取不大於8k.

final class Segment {
/** The size of all segments in bytes. */
static final int SIZE = 8192;

http2中每次讀取不大於8k.

然後還漏瞭一點:

socket.setSoTimeout(chain.readTimeoutMillis());


這行代碼什麼意思呢?

setSotimeout(10000)是表示如果對方連接狀態10秒沒有收到數據的話強制斷開客戶端。
如果想要長連接的話,可以使用心跳包來通知服務器,也就是我沒有發給你數據,但是我告訴你我還活著.

最後,如果超時時間設置的如果是0,那麼代表超時時長為無限.

附上okhttp的默認超時時間

總結

到此這篇關於OkHttp的超時時間的文章就介紹到這瞭,更多相關OkHttp超時時間內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: