OkHttp源码解析(二)——整体流程(下)
2016-07-28 00:03
579 查看
1.前言
这一篇将说一下请求体的写入以及相应的读取过程。2.请求体写入过程
HttpEngine#readResponse这个方法下有下面的一块代码片段。
else if (!callerWritesRequestBody) { networkResponse = new NetworkInterceptorChain(0, networkRequest, streamAllocation.connection()).proceed(networkRequest); }
callerWritesRequestBody在初始化的时候为false,我们接着看NetworkInterceptorChain的proceed方法,会发现下面一段代码。
if (permitsRequestBody(request) && request.body() != null) { Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength()); BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut); request.body().writeTo(bufferedRequestBody); bufferedRequestBody.close(); }
permitsRequestBody 判断是否允许body
判断body是否为空
这里返回的requestBodyOut对象是对我们创建socket的时候的那个sike对象的包装。这里我偷个懒,具体的代码就不贴了。感兴趣的去http1xstream下追踪看看。这样,我们就把请求体也写入进去了。
3.读取响应的过程
HttpEngine#readNetworkResponse在该方法中,有下面代码片段。
Response networkResponse = httpStream.readResponseHeaders() .request(networkRequest) .handshake(streamAllocation.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); if (!forWebSocket) { networkResponse = networkResponse.newBuilder() .body(httpStream.openResponseBody(networkResponse)) .build(); }
我们重点关注httpStream.openResponseBody方法。
4.Http1xStream
Http1xStream#openResponseBody,该方法如下。@Override public ResponseBody openResponseBody(Response response) throws IOException { Source source = getTransferStream(response); return new RealResponseBody(response.headers(), Okio.buffer(source)); }
在getTransferStream方法中,通过层层的调用,构造出一个Source对象,并将其和response.headers组装成真正的响应体。
5.Http2XStream
Http2xStream#openResponseBody@Override public ResponseBody openResponseBody(Response response) throws IOException { Source source = new StreamFinishingSource(stream.getSource()); return new RealResponseBody(response.headers(), Okio.buffer(source)); }
看到,关键点在于stream.getSource,而这个stream是什么呢?这是一个FramedStrem对象,并且是在writeRequestHeaders方法中初始化的。相应代码如下
stream = framedConnection.newStream(requestHeaders, permitsRequestBody, hasResponseBody);
而framedConnection是在HttpStrem#newStream方法中初始化并传入的
resultStream = new Http2xStream(this, resultConnection.framedConnection);
而resultConnection.framedConnection则是RealConnection的framedConnection了,这个对象是在什么时候初始化的呢?是在建立连接的时候,在establishProtocol方法中。
if (protocol == Protocol.SPDY_3 || protocol == Protocol.HTTP_2) { socket.setSoTimeout(0); // Framed connection timeouts are set per-stream. FramedConnection framedConnection = new FramedConnection.Builder(true) .socket(socket, route.address().url().host(), source, sink) .protocol(protocol) .listener(this) .build(); framedConnection.start(); // Only assign the framed connection once the preface has been sent successfully. this.allocationLimit = framedConnection.maxConcurrentStreams(); this.framedConnection = framedConnection; } else { this.allocationLimit = 1; }
注意,上面讲socket,source,sink都传了进去。
现实new了一个对象,病start,并且把这个对象传给RealConnection的framedConnection。因此,我们看下start方法干了什么,
new Thread(readerRunnable).start();
readerRunnable = new Reader(variant.newReader(builder.source, client));
这里的Reader是一个Runnable是一个实现NamedRunnable的对象没我们需要看下他的execute方法。
@Override protected void execute() { ErrorCode connectionErrorCode = ErrorCode.INTERNAL_ERROR; ErrorCode streamErrorCode = ErrorCode.INTERNAL_ERROR; try { if (!client) { frameReader.readConnectionPreface(); } while (frameReader.nextFrame(this)) { } connectionErrorCode = ErrorCode.NO_ERROR; streamErrorCode = ErrorCode.CANCEL; } catch (IOException e) { connectionErrorCode = ErrorCode.PROTOCOL_ERROR; streamErrorCode = ErrorCode.PROTOCOL_ERROR; } finally { try { close(connectionErrorCode, streamErrorCode); } catch (IOException ignored) { } Util.closeQuietly(frameReader); } }
可以在while里看到frameReader.nextFrame(this),而这个framewReader是Http2的Reader对象,我们看下他的方法。
variant = new Http2();
Reader(BufferedSource source, int headerTableSize, boolean client) { this.source = source; this.client = client; this.continuation = new ContinuationSource(this.source); this.hpackReader = new Hpack.Reader(headerTableSize, continuation); }
而在在nextFrame方法里,我们就能看到读取的过程了。代码片段如下。
最后来张截图压压惊。 ![这里写图片描述](http://img.blog.csdn.net/20160728000306967)
相关文章推荐
- AndroidStudio添加网络授权
- [网络通信]socket编程中检查connect是否成功
- [网络通信]使用fork的TCP通信服务端重起bind问题
- 互联网技术革新:你的网站升级到https了吗?
- httpClient application/json使用
- 1.1.2 计算机网络的组成
- 网编基础(4)网络下载音乐和视频
- 《用tcp/ip进行网际互联》第9章 无分类和子网地址扩展(CIDR)
- 1.1.1 计算机网络的概念
- Scrapy学习大全
- Android视频/音频缓存框架AndroidVideoCache(Okhttp)
- eclipse配置tomcat,访问http://localhost:8080出现404错误
- 网络编程3要素
- Http协议备忘录
- IP分片和TCP分片 MTU和MSS(转)
- IP分片和TCP分片 MTU和MSS(转)
- Apache Mesos 底层网络通信库 libprocess 分析
- 网络数据请求
- linux网络基本之ip命令
- TCP/IP协议(1)——基本概念