网络访问_OKHttp
OKHttp技术结构
OKHttp技术点.jpg建造者设计模式创建OKHttpClient客户端,当与Retrofit一起使用时,Retrofit建造者Build#client方法将OkHttpClient传给Retrofit。
1. Okhttp线程池与任务分发
一个完整的Http请求从App客户端发送到服务器,不占用主线程资源,在多个请求并发下条件,线程池负责分配线程,执行请求(任务)。客户端将请求封装成Request。
Okhttp任务分发示意图如下所示:
1.1 请求者RealCall
OkHttp为每一个请求创建一个RealCall。
OkHttpClient#newCall方法。
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
Call是接口类型,内部工厂接口Factory,Factory#newCall方法负责创建Call,OkHttpClient实现Call.Factory工厂接口。
RealCall负责一个具体请求的Http事务,同步或异步,交给OkHttpClient的Dispatcher分发处理。
RealCall#execute方法。同步请求。
@Override
public Response execute() throws IOException {
synchronized (this) {
...
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();//同步,耗时处
return result;
} finally {
client.dispatcher().finished(this);
}
}
RealCall#enqueue方法。异步请求。
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
...
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
1.2 分发者Dispatcher
Dispatcher控制多个Http请求的节奏,负责RealCall的并发,等待与运行队列管理,线程池调度。
-
异步请求分发
Dispatcher#enqueue方法。
synchronized void enqueue(AsyncCall call) {
//maxRequests=64,maxRequestsPerHost=5
if (runningAsyncCalls.size() < maxRequests &&
runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);//加入运行队列
executorService().execute(call);//线程池执行任务
} else {
readyAsyncCalls.add(call);
}
}
由maxRequests和maxRequestsPerHost决定等待还是处理。
maxRequests:最大请求数量。
maxRequestsPerHost:每个主机最大并发请求数量。
若满足并发数量,将AsyncCall任务加入运行队列,交给线程池处理。
若不满足并发数量,将AsyncCall任务加入等待队列。
Dispatcher内部线程池调度任务,AsyncCall是RealCall的内部类,Runnable类型。
- 同步请求分发
Dispatcher#executed方法。
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
当前线程执行同步请求,同步队列保存RealCall,而不是Runnable任务。
将RealCall加入同步队列,代表这个RealCall正在执行,耗时点在RealCall#getResponseWithInterceptorChain方法。
- 请求结束
Dispatcher#finish方法。
//异步
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//同步
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
同步请求结束时,从同步队列中删除RealCall。
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();//异步
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
异步请求结束时,从运行队列中删除AsyncCall任务,然后触发Dispatcher#promoteCalls方法。
Dispatcher#promoteCalls方法。
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();//满足条件,等待队列删除
runningAsyncCalls.add(call);//加入运行中队列
executorService().execute(call);//开始执行
}
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
查找等待队列的任务,遍历,满足并发数量条件时,每个等待队列的任务都会处理,从等待队列删除,加入运行队列,交给线程池。不满足并发条件时,不处理。
RealCall请求执行流程图如下所示。 RealCall请求执行流程示意图.jpg每次异步/同步请求结束后,均调用Dispatcher#finish方法,异步请求在AsyncCall#execute最后调用,异步让等待中的任务得到机会。
1.3 Okhttp线程池(缓存线程池)
Dispatcher#executorService方法。
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60,
TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),
Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
ThreadPoolExecutor是一个阀值[0, Integer.MAX_VALUE]的线程池。
- 不保留corePoolSize核心线程,最大可创建线程MAX_VALUE。
- 每个工作线程keepAliveTime设置60s,保持60s存活期,线程复用。
- SynchronousQueue阻塞队列不存储元素,是一个管道。
大量并发请求时,线程池启动多个工作线程,确保每个任务都有线程及时处理,工作线程都是临时线程。每个线程执行NamedRunnable#run方法,AsyncCall继承NamedRunnable,实现execute抽象方法。
AsyncCall#execute方法。
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//触发RealCall的方法,AsyncCall定义在RealCall类内部。
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
....
} finally {
//异步请求结束后finish。
client.dispatcher().finished(this);
}
}
RealCall#getResponseWithInterceptorChain方法,同步和异步都会触发,耗时操作,获取Response。
AsyncCall构造方法创建时,将外部Callback传入,获取Response成功或失败均回调Callback。
2. OKHttp拦截器设计
拦截器列表如下图所示 Interceptor列表.jpg通过创建一系列拦截器链式处理获取Response。缓存,链路连接都通过责任链设计实现。
RealCall#getResponseWithInterceptorChain方法。
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
在拦截器之间传递的链对象RealInterceptorChain,index初始是0,传入原始请求originalRequest与拦截器列表interceptors。
触发RealInterceptorChain#proceed方法,在proceed方法中找到interceptors链表index索引处的拦截器,第index个拦截器Interceptor,新建一个index++的RealInterceptorChain对象,触发Interceptor#intercept方法,传递Chain。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
..
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
//抛出异常
}
if (response == null) {
//抛出异常
}
return response;
}
每一个拦截器Interceptor#intercept方法。
- 处理Request。
- 触发Chain#proceed方法。
- 处理Response。
每一个Chain#proceed方法。
- 找到下一个拦截器。
- 创建一个新RealInterceptorChain。
- 触发Interceptor#intercept传递给Interceptor。
一直递归调用,当index++到最后一个CallServerInterceptor拦截器,真正向服务器发送数据,获取Response,然后递归一层层按原路返回Response。
Okhttp拦截器执行流程.png拦截器责任链设计是一个递归调用的过程。
Chain是链传递的对象,每个Chain在proceed处理时,创建另一个index增1的Chain链对象,传递给下一项Interceptor。
每一项Interceptor在intercept时,先拦截处理Request,再调用Chain的proceed方法,最后处理Response。
责任链设计类。
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
proceed方法流入Request,流出Response。每一个拦截器的目的是层层截断流入与流出,先截流,加工处理,再放流。
3. OKHttp缓存设计
拦截器CacheInterceptor处理缓存。
3.1 缓存接口InternalCache
Cache是Okhttp设计的缓存类,内部定义了缓存接口InternalCache的实现,在Cache中包含一些与InternalCache相同的方法。
Cache内部实现的InternalCache接口。
final InternalCache internalCache = new InternalCache() {
@Override
public Response get(Request request) throws IOException {
return Cache.this.get(request);
}
@Override
public CacheRequest put(Response response) throws IOException {
return Cache.this.put(response);
}
@Override
public void remove(Request request) throws IOException {
Cache.this.remove(request);
}
...
};
InternalCache接口设计的方法用于对外暴漏Cache缓存方法的实现。
在拦截器CacheInterceptor创建时,使用OkHttpClient中的缓存。OkHttpClient中包含Cache与InternalCache。OkHttpClient#internalCache方法,优先使用OkHttpClient中Cache的internalCache,其次是internalCache。
OkHttpClient#internalCache方法。
final Cache cache;
final InternalCache internalCache;
InternalCache internalCache() {
return cache != null ? cache.internalCache : internalCache;
}
DiskLruCache存储缓存。
3.2 缓存策略
CacheInterceptor#intercept方法。
@Override
public Response intercept(Chain chain) throws IOException{
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
....
}
首先根据InternalCache查找缓存Response。
创建CacheStrategy#Factory工厂,负责创建缓存策略CacheStrategy。Factory是CacheStrategy内部类,构造方法传入now(当前时间),request(发送请求),cacheCandidate(缓存Response)。
CacheStrategy#Factory#get方法。
public CacheStrategy get() {
CacheStrategy candidate = getCandidate();
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
return new CacheStrategy(null, null);
}
return candidate;
}
Factory中存储Request、cacheResponse以及从Response的Header解析出来的servedDate、expires。Factory#getCandidate方法根据他们的值创建缓存策略。
CacheStrategy#Factory#getCandidate方法。
private CacheStrategy getCandidate() {
if (cacheResponse == null) {//1
return new CacheStrategy(request, null);
}
if (request.isHttps() && cacheResponse.handshake() == null) {//2
return new CacheStrategy(request, null);
}
if (!isCacheable(cacheResponse, request)) {//3
return new CacheStrategy(request, null);
}
CacheControl requestCaching = request.cacheControl();
if (requestCaching.noCache() || hasConditions(request)) {//4
return new CacheStrategy(request, null);
}
...
}
几类简单的策略
- Response缓存是空,说明未存储缓存,策略中仅包含Request,不包含缓存Response。
- Request是https协议并且Response的handshake是空,策略中仅包含Request。
- CacheControl设置为noStore状态,说明不存储,策略中仅包含Request。
- 请求中包含noCache标志,或者请求中Header的If-Modified-Since或If-None-Match非空,策略中仅包含Request。
- 当小于最大期限时,使用缓存,策略中仅包含Response。
根据CacheStrategy策略内部networkRequest与cacheResponse,若无需访问网络,则构建Response返回,若需要访问网络,继续责任链调用,下一个拦截器是ConnectInterceptor,建立访问链路,最后获取的Response会视情况存入Cache。
4. OKHttp连接链路
拦截器ConnectInterceptor连接链路。
4.1 StreamAllocation
ConnectInterceptor#intercept方法。
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();//从Chain中获取Request
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
//处理返回Response
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
- StreamAllocation在RetryAndFollowUpInterceptor#intercept方法中创建,在Chain#proceed中传递给下一个Chain对象,当Chain到达ConnectInterceptor时,从Chain中获取。
RetryAndFollowUpInterceptor#intercept方法代码段。
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(request.url()), callStackTrace);
每个RealCall对应一个拦截器列表(多个拦截器对象),因此,每个RealCall分配一个StreamAllocation。负责具体网络链路分配、建立和访问。
StreamAllocation#newStream方法。
public HttpCodec newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
...
try {
RealConnection resultConnection = findHealthyConnection(connectTimeout,
readTimeout,writeTimeout, connectionRetryEnabled,
doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
}
}
-
newStream方法通过分配策略寻找一个真正的链接RealConnection,初始化HttpCodec对象。
-
最后Chain#proceed方法将RealConnection,HttpCodec和StreamAllocation传递给下一个拦截器CallServerInterceptor。
StreamAllocation#findConnection方法。
private RealConnection findConnection(int connectTimeout, int readTimeout,
int writeTimeout,boolean connectionRetryEnabled) throws IOException {
Route selectedRoute;
synchronized (connectionPool) {
//先使用StreamAllocation内部保存的RealConnection
RealConnection allocatedConnection = this.connection;
if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
return allocatedConnection;
}
//连接池中寻找
Internal.instance.get(connectionPool, address, this, null);
if (connection != null) {
return connection;
}
selectedRoute = route;
}
...
RealConnection result;
synchronized (connectionPool) {
Internal.instance.get(connectionPool, address, this, selectedRoute);
if (connection != null) return connection;
//创建RealConnection
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
acquire(result);
}
result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
//入池
Internal.instance.put(connectionPool, result);
...
}
closeQuietly(socket);
return result;
}
分配获取策略
- 优先考虑StreamAllocation内部保存的RealConnection连接。
- 其次从连接池ConnectionPool中获取。
- 创建RealConnection,保存在StreamAllocation内部,入池。
OkHttpClient#Internal对象,(静态代码段)。
static {
Internal.instance = new Internal() {
@Override public
RealConnection get(ConnectionPool pool, Address address,StreamAllocation streamAllocation, Route route) {
return pool.get(address, streamAllocation, route);
}
@Override
public void put(ConnectionPool pool, RealConnection connection) {
pool.put(connection);
}
....//其他方法.
};
}
从ConnectionPool连接池中获取RealConnection。
StreamAllocation#acquire方法。
public void acquire(RealConnection connection) {
..
this.connection = connection;
connection.allocations.add(new StreamAllocationReference(this, callStackTrace));
}
RealConnection内部存储一个引用它的StreamAllocation的弱引用列表,多个StreamAllocation公用RealConnection连接链路。
从连接池获取时,RealConnection的allocationLimit限制StreamAllocation弱引用数量,遍历连接池中每个RealConnection,若Address相等且StreamAllocationReference数量小于限制,则该连接可用。若RealConnection的限制数量已达到allocationLimit,该链接不能再被StreamAllocation使用。
将获取的RealConnection返回,设置成StreamAllocation内部connection,然后将引用它的StreamAllocation加入allocations弱引用列表,代表又一个StreamAllocation使用了该链路。
若不满足条件池中连接不可用,新建链路,新建的RealConnection同样赋值给StreamAllocation内部,并将StreamAllocation加入弱引用列表,最后入连接池。
OkHttp连接链路意图如下所示。
StreamAllocation负责管理RealConnection、HttpCodec,操作连接池,分配、取消、释放连接。多个请求StreamAllocation可复用RealConnection。
4.2 RealConnection
RealConnection代表一个真正的链路,功能包括BufferedSource,BufferedSink,路由,socket,协议,Handshake信息。
建立Socket连接
新建RealConnection先执行RealConnection#connect方法,触发connectSocket,建立连接。
RealConnection#connectSocket方法。
private void connectSocket(int connectTimeout, int readTimeout) throws IOException {
Proxy proxy = route.proxy();
Address address = route.address();
//创建Socket
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
? address.socketFactory().createSocket()
: new Socket(proxy);
rawSocket.setSoTimeout(readTimeout);
try {
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
} catch (ConnectException e) {
ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
ce.initCause(e);
throw ce;
}
source = Okio.buffer(Okio.source(rawSocket));
sink = Okio.buffer(Okio.sink(rawSocket));
}
Platform#connectSocket触发Socket#connect方法,连接Socket,若连接成功,与服务器建立一个Socket连接,若连接失败抛出异常。
Platform#connectSocket方法。
public void connectSocket(Socket socket, InetSocketAddress address, int connectTimeout) throws IOException {
socket.connect(address, connectTimeout);
}
Okio根据Socket获取读写缓冲区,负责具体读写底层Request与Response的Header与Body消息,由Okio框架的BufferedSource与BufferedSink完成。
创建HttpCodec
RealConnection#newCodec方法。
public HttpCodec newCodec(OkHttpClient client, StreamAllocation streamAllocation)
throws SocketException {
if (http2Connection != null) {
return new Http2Codec(client, streamAllocation, http2Connection);
} else {
socket.setSoTimeout(client.readTimeoutMillis());
source.timeout().timeout(client.readTimeoutMillis(), MILLISECONDS);
sink.timeout().timeout(client.writeTimeoutMillis(), MILLISECONDS);
return new Http1Codec(client, streamAllocation, source, sink);
}
}
如果协议采用Protocol.HTTP_2,则Http2Connection存在,创建Http2Codec,否则创建Http1Codec,将BufferedSource和BufferedSink封装到Http1Codec。
4.3 ConnectionPool连接池管理
ConnectionPool连接池负责链路管理,默认支持5个并发keepalive,默认链路生命为5分钟,即链路数据传输完毕后可保持5分钟空闲的存活时间。
自动清除线程会查找超过5分钟的链路,关闭链路即关闭socket。
- ArrayDeque双向队列保存RealConnection连接。线性连续空间,双向开口,可高效在头尾两端插入删除,同时具有队列和栈性质,常用缓存。
- get/put连接池操作方法,ConnectionPool#put时触发清理任务cleanupRunnable。
ConnectionPool#put方法。
void put(RealConnection connection) {
if (!cleanupRunning) {
cleanupRunning = true;
executor.execute(cleanupRunnable);//执行清理任务
}
connections.add(connection);//加入连接池队列
}
- 线程池负责执行cleanupRunnable任务,清理连接,put操作时,若cleanupRunning标志位是false,说明任务未被执行,主动调用,进入while死循环(除非主动退出),实质上是一个阻塞的清理任务。若任务循环未主动退出,下次put将不会触发。
cleanupRunnable任务#run方法。
while (true) {
long waitNanos = cleanup(System.nanoTime());
if (waitNanos == -1) return;
if (waitNanos > 0) {
long waitMillis = waitNanos / 1000000L;
waitNanos -= (waitMillis * 1000000L);
synchronized (ConnectionPool.this) {
try {
ConnectionPool.this.wait(waitMillis, (int) waitNanos);
} catch (InterruptedException ignored) {
}
}
}
}
首先cleanup清理方法,返回值waitNanos是下次清理的间隔时间,然后调用wait(timeout)等待,释放锁与时间片。等待waitNanos时间后,继续while循环cleanup清理。
ConnectionPool清理任务流程图如下所示。 ConnectionPool清理任务处理流程.jpgwaitNanos代表等待下一次清理的时间间隔,-1表示不需要再次清理,退出循环,0表示立即再次清理。
ConnectionPool#cleanup方法代码段。
for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
RealConnection connection = i.next();
// 是否在使用
if (pruneAndGetAllocationCount(connection, now) > 0) {
inUseConnectionCount++;
continue;
}
idleConnectionCount++;
//找空闲最长的
long idleDurationNs = now - connection.idleAtNanos;
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
遍历,pruneAndGetAllocationCount方法查看连接是否在使用。inUseConnectionCount:正在使用数量。若正在使用,自增。idleConnectionCount:空闲的数量。若连接未使用,自增。idleDurationNs:空闲的连接,计算已经空闲时间,找到空闲时间最长的链接。
ConnectionPool#cleanup方法代码段。
if (longestIdleDurationNs >= this.keepAliveDurationNs
|| idleConnectionCount > this.maxIdleConnections) {
connections.remove(longestIdleConnection);
} else if (idleConnectionCount > 0) {
return keepAliveDurationNs - longestIdleDurationNs;
} else if (inUseConnectionCount > 0) {
return keepAliveDurationNs;
} else {
cleanupRunning = false;
return -1;
}
closeQuietly(longestIdleConnection.socket());
return 0;
- 若longestIdleDurationNs(最长空闲时间)大于5分钟或空闲连接数量超过5(默认),则将该链接删除,返回0,下次立即清理。
-若最长空闲时间不足5分钟,但有空闲连接(未大于5个),返回剩余时间timeout(距离5分钟还有多久),清理线程阻塞timeout再次清理。 - 若不存在空闲链接,且存在使用链接,返回最大等待时间5分钟。
- 空闲和正在使用的连接均不存在,无需清理,返回-1,线程退出。设置任务cleanupRunning标志位false,下次put会重新唤起该任务。
清理过程
- 从连接池队列ArrayDeque中删除该项连接。
- closeQuietly关闭socket。
判断连接正在使用
找到RealConnection内部Reference<StreamAllocation>列表,遍历,若reference.get()存在,说明有StreamAllocation正引用RealConnection,正在使用,若reference.get()不存在,说明StreamAllocation已经被Jvm清理,同时从references列表中删除该项reference,遍历完毕,若references列表为空,说明references的弱引用都不存在,没有StreamAllocation使用该连接。
5. OkHttp数据流
拦截器CallServerInterceptor负责网络数据流读写。
ConnectInterceptor拦截器利用StreamAllocation创建RealConnection(或复用)与HttpCodec,通过Chain#proceed方法封装到一个新Chain对象,传递给下一个拦截器CallServerInterceptor。
CallServerInterceptor#intercept方法。
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//获取前一个拦截器ConnectInterceptor创建的HttpCpdec
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
//利用BufferSink写入
httpCodec.writeRequestHeaders(request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
...
}
//Sink的flush
httpCodec.finishRequest();
//利用Source读取Response的Header
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
...
...
return response;
}
通过底层IO操作库Okio,HttpCodec封装了BufferedSource和BufferedSink,负责数据流缓冲区的读写操作,数据源是RealConnection的Socket。BufferedSink负责写入,BufferedSource负责读取。
任重而道远