OkHttp完全解析(九)源码解析二
2015-11-25 17:32
483 查看
上一篇文章里我们大致分析了OkHttp整个请求的流程,重点分析了具体发送请求前都做了哪些操作,这篇文章我们将继续上篇的内容,看看在发送请求过程中做了什么,看了上篇文章的应该都知道,我们将从HttpEngine的sendRequest入手看是如何操作的
上面的代码先是针对请求策略去判断是否走网络,若不走网络networkResponse为空直接去生成userReponse,否则就进入网络请求状态并且在第28行进行建立连接操作,这个操作比较重要,我们进去看看
上面的代码是跟服务器建立链接的过程,在createNextConnection里先去线程池里找是否有之前请求过该Address且还在存活时间里的connection否则新建一个,并调用Internal.instance.connectAndSetOwner(this.client, connection, this, this.networkRequest);,这个代码最后会执行到Connection里的
上面26行处我们建立的httpconnection,它的构造函数将根据传入的socket生成source(socket的输入流用来读)和s**ink(socket的输出流用来写)**
然后我们继续回到sendRequest看看connect后做了什么,sendRequest()代码31行新建HttpEngine,然后在32行处的if判断,我们可以从OKHttp源码解析(一) 文章末尾的代码22行处看到传入的callerWritesRequestBody为false(第四个参数),requestBodyOut为null(最后一个参数),因此这个if判断在这里并不会执行。
分析到这里我们基本把整个发送请求的过程分析完了,又是大段大段贴代码,因为这部分其实逻辑比较清楚,代码也比较容易看懂,重要的部分都注释出来,下一篇我们将继续来讲解readResponse。
publicvoid sendRequest() throws RequestException, RouteException, IOException { if(this.cacheStrategy == null) { if(this.transport != null) { thrownew IllegalStateException(); } else { Request request = this.networkRequest(this.userRequest); //读取用户设置的缓存 InternalCache responseCache = Internal.instance.internalCache(this.client); //从缓存中读取之前相同请求得到的Response Response cacheCandidate = responseCache != null?responseCache.get(request):null; long now = System.currentTimeMillis(); //根据请求和缓存结果(可能为null)去得到缓存策略this.cacheStrategy = (new Factory(now, request, cacheCandidate)).get(); //如果请求策略为只要缓存则networkRequest,cacheResponse都为空,大部分条件都会得到networkRequest就是request,cacheResponse为空this.networkRequest = this.cacheStrategy.networkRequest; this.cacheResponse = this.cacheStrategy.cacheResponse; if(responseCache != null) { responseCache.trackResponse(this.cacheStrategy); } if(cacheCandidate != null && this.cacheResponse == null) { Util.closeQuietly(cacheCandidate.body()); } if(this.networkRequest != null) { if(this.connection == null) { //建立连接this.connect(); } //得到HttpTransport(Http请求)this.transport = Internal.instance.newTransport(this.connection, this); //根据条件将一些执行请求头部的写入,具体的写入会调动到httpConnection的sink(就是一个socket请求的outputstream,具体后面分析)去writeif(this.callerWritesRequestBody && this.permitsRequestBody() && this.requestBodyOut == null) { long contentLength = OkHeaders.contentLength(request); if(this.bufferRequestBody) { if(contentLength > 2147483647L) { thrownew IllegalStateException("Use setFixedLengthStreamingMode() or setChunkedStreamingMode() for requests larger than 2 GiB."); } if(contentLength != -1L) { this.transport.writeRequestHeaders(this.networkRequest); this.requestBodyOut = new RetryableSink((int)contentLength); } else { this.requestBodyOut = new RetryableSink(); } } else { //进入这个判断说明不需要走网络请求,直接读取缓存 this.transport.writeRequestHeaders(this.networkRequest); this.requestBodyOut = this.transport.createRequestBody(this.networkRequest, contentLength); } } } else { if(this.connection != null) { Internal.instance.recycle(this.client.getConnectionPool(), this.connection); this.connection = null; } if(this.cacheResponse != null) { //组装缓存数据成Responsethis.userResponse = this.cacheResponse.newBuilder().request(this.userRequest).priorResponse(stripBody(this.priorResponse)).cacheResponse(stripBody(this.cacheResponse)).build(); } else { //只要缓存的数据但之前又没有缓存则抛出 504的Responsethis.userResponse = (new Builder()).request(this.userRequest).priorResponse(stripBody(this.priorResponse)).protocol(Protocol.HTTP_1_1).code(504).message("Unsatisfiable Request (only-if-cached)").body(EMPTY_BODY).build(); } //解压请求结果this.userResponse = this.unzip(this.userResponse); } } } }
上面的代码先是针对请求策略去判断是否走网络,若不走网络networkResponse为空直接去生成userReponse,否则就进入网络请求状态并且在第28行进行建立连接操作,这个操作比较重要,我们进去看看
privatevoid connect() throws RequestException, RouteException { if(this.connection != null) { thrownew IllegalStateException(); } else { if(this.routeSelector == null) { //建立一个Address,用来记录web服务器,以及要连接服务器需要的一些静态配置比如端口号,网络协议等this.address = createAddress(this.client, this.networkRequest); try { //得到路由选择器,用于记录连接服务器的一些动态配置,比如查询DNS的ip,代理服务器,TLS协议版本this.routeSelector = RouteSelector.get(this.address, this.networkRequest, this.client); } catch (IOException var2) { thrownew RequestException(var2); } } //得到httpConnectionthis.connection = this.nextConnection(); this.route = this.connection.getRoute(); } } private Connection nextConnection() throws RouteException { Connection connection = this.createNextConnection(); //将connection设置到okhttpclient Internal.instance.connectAndSetOwner(this.client, connection, this, this.networkRequest); return connection; } private Connection createNextConnection() throws RouteException { //拿到连接池,如果用户没有设置pool,将得到默认的ConnectionPool ConnectionPool pool = this.client.getConnectionPool(); Connection e; //根据address和存活时间等条件找到是否有之前的connection可用while((e = pool.get(this.address)) != null) { if(this.networkRequest.method().equals("GET") || Internal.instance.isReadable(e)) { return e; } Util.closeQuietly(e.getSocket()); } try { Route e1 = this.routeSelector.next(); //没有满足条件的Connection建立新的connectionreturnnew Connection(pool, e1); } catch (IOException var3) { thrownew RouteException(var3); } }
上面的代码是跟服务器建立链接的过程,在createNextConnection里先去线程池里找是否有之前请求过该Address且还在存活时间里的connection否则新建一个,并调用Internal.instance.connectAndSetOwner(this.client, connection, this, this.networkRequest);,这个代码最后会执行到Connection里的
void connect(int connectTimeout, int readTimeout, int writeTimeout, Request request, List<ConnectionSpec> connectionSpecs, boolean connectionRetryEnabled) throws RouteException { if(this.connected) { thrownew IllegalStateException("already connected"); } else { //建立Socket连接器 SocketConnector socketConnector = new SocketConnector(this, this.pool); ConnectedSocket connectedSocket; if(this.route.address.getSslSocketFactory() != null) { connectedSocket = socketConnector.connectTls(connectTimeout, readTimeout, writeTimeout, request, this.route, connectionSpecs, connectionRetryEnabled); } else { if(!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) { thrownew RouteException(new UnknownServiceException("CLEARTEXT communication not supported: " + connectionSpecs)); } //建立socket并进行socket.connect发起对服务器的连接 connectedSocket = socketConnector.connectCleartext(connectTimeout, readTimeout, this.route); } this.socket = connectedSocket.socket; this.handshake = connectedSocket.handshake; //这里我们最终会得到protocol为Protocol.HTTP_1_1this.protocol = connectedSocket.alpnProtocol == null?Protocol.HTTP_1_1:connectedSocket.alpnProtocol; try { if(this.protocol != Protocol.SPDY_3 && this.protocol != Protocol.HTTP_2) { //建立httpConnectionthis.httpConnection = new HttpConnection(this.pool, this, this.socket); } else { this.socket.setSoTimeout(0); this.spdyConnection = (new Builder(this.route.address.uriHost, true, this.socket)).protocol(this.protocol).build(); this.spdyConnection.sendConnectionPreface(); } } catch (IOException var10) { thrownew RouteException(var10); } this.connected = true; } }
上面26行处我们建立的httpconnection,它的构造函数将根据传入的socket生成source(socket的输入流用来读)和s**ink(socket的输出流用来写)**
public HttpConnection(ConnectionPool pool, Connection connection, Socket socket) throws IOException { this.pool = pool; this.connection = connection; this.socket = socket; this.source = Okio.buffer(Okio.source(socket)); this.sink = Okio.buffer(Okio.sink(socket)); }代码看到这里我们知道了connect的整个代码流程,得到socket,连接,建立输入输出流。[/code]
然后我们继续回到sendRequest看看connect后做了什么,sendRequest()代码31行新建HttpEngine,然后在32行处的if判断,我们可以从OKHttp源码解析(一) 文章末尾的代码22行处看到传入的callerWritesRequestBody为false(第四个参数),requestBodyOut为null(最后一个参数),因此这个if判断在这里并不会执行。
分析到这里我们基本把整个发送请求的过程分析完了,又是大段大段贴代码,因为这部分其实逻辑比较清楚,代码也比较容易看懂,重要的部分都注释出来,下一篇我们将继续来讲解readResponse。
相关文章推荐
- OkHttp完全解析(八)源码解析一
- OkHttp完全解析(七)SPDY协议详细介绍
- OkHttp完全解析(六)拦截器
- 神经网络(4)---神经网络是如何帮助我们学习复杂的nonlinear hypotheses
- [连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计
- OkHttp完全解析(五)HTTPS
- Linux TCP服务端接收连接数量突破65535的方法
- OkHttp完全解析(四)连接Connections
- http server与tomcat的区别
- OkHttp完全解析(三)并发
- OkHttp完全解析(一)OkHttp简介
- HTTP服务器响应状态信息
- java 实现https请求
- Https(SSL/TLS)原理详解
- Hello Bonjour!实现零配置网络联网的解决方案
- 安卓开发之动态注册网络监听广播
- 虚拟机网络设置
- java基础之网络(TCP-Socket)
- iOS9 HTTP 不能正常使用的解决办法
- Swift网络库Alamofire