OKHttp原码分析(六)之RealConnection
来源:互联网 发布:c语言入门经典txt下载 编辑:程序博客网 时间:2024/05/17 22:14
一,概述
okhttp是底层实现框架,与httpURLconnection是同一级别的。OKHttp底层建立网络连接的关键就是RealConnection类。RealConnection类底层封装socket,是真正的创建连接者。分析这个类之后就明白了OKHttp与httpURLconnection的本质不同点。
RealConnection是底层类,都是间接的被其他类调用,所以到目前为止还未发现使用这个类的地方。不要感觉到源码分析断层了,因为这个类太重要了,所以不得不拿出来单独分析。先记住这个类,等下一篇blog分析httpStream时就会将RealConnection与其他部分连接起来。
二,RealConnection对象的创建。
RealConnection 对象在StreamAllocation 类中得到。
有人说我是怎么知道RealConnection对象是在StreamAllocation 类中得到,因为我已经把源码看过一遍了,所以找到了这个地方。看这篇blog的小伙伴只需先记着,下一篇blog就会有说明。
得到RealConnection 对象的代码是在newStream方法中,核心代码是:
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
findHealthyConnection方法又调用了findConnection方法。findConnection方法的源码是:
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout, boolean connectionRetryEnabled) throws IOException { Route selectedRoute; synchronized (connectionPool) { ;//创建RealConnection对象。 RealConnection newConnection = new RealConnection(selectedRoute); acquire(newConnection); ;//连接网络 newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(), connectionRetryEnabled); routeDatabase().connected(newConnection.route()); return newConnection; }
这段代码主要做了两件事情,一是创建RealConnection 对象,二是建立网络连接。
下面看建立网络连接的代码。
三,建立网络连接(重点)
建立网络连接使用的代码是RealConnection 类的connect方法。
connect方法又调用了buildConnection方法。
buildConnection方法的源码是:
private void buildConnection(int connectTimeout, int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { connectSocket(connectTimeout, readTimeout);//连接socket establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);//建立协议 }
首先看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 { ;//连接socket Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout); } catch (ConnectException e) { throw new ConnectException("Failed to connect to " + route.socketAddress()); } source = Okio.buffer(Okio.source(rawSocket));//从socket中获取source 对象。 sink = Okio.buffer(Okio.sink(rawSocket));//从socket中获取sink 对象。 }
这个方法里做了三件事情:
1,创建socket对象。
2,连接socket。
3,使用okio包从socket中得到source 对象和sink 对象。
下面看下Okio.source(rawSocket)的原码:
public static Source source(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); Source source = source(socket.getInputStream(), timeout);//从socket中得到输入流对象。 return timeout.source(source); }
看到这儿大家会有种熟悉的感觉,这不就是我们熟悉的socket编码吗?对,这就是面向socket编程。
所以OKHttp本质是封装的socket。
四,建立协议
建立协议的方法是establishProtocol。方法原码如下:
private void establishProtocol(int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { if (route.address().sslSocketFactory() != null) { connectTls(readTimeout, writeTimeout, connectionSpecSelector); } else { protocol = Protocol.HTTP_1_1; socket = rawSocket; } 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; } }
从代码中可以看到,使用哪一种协议主要看route.address().sslSocketFactory() != null的返回值是true还是false。
RealConnection 的route对象来自于streamAllocation对象,streamAllocation对象在RetryAndFollowUpInterceptor类的intercept方法中被创建。创建streamAllocation对象的核心代码是:
streamAllocation = new StreamAllocation( client.connectionPool(), createAddress(request.url()));
下面看createAddress方法的源码:
private Address createAddress(HttpUrl url) { SSLSocketFactory sslSocketFactory = null; HostnameVerifier hostnameVerifier = null; CertificatePinner certificatePinner = null; if (url.isHttps()) { sslSocketFactory = client.sslSocketFactory(); hostnameVerifier = client.hostnameVerifier(); certificatePinner = client.certificatePinner(); } return new Address(url.host(), url.port(), client.dns(), client.socketFactory(), sslSocketFactory, hostnameVerifier, certificatePinner, client.proxyAuthenticator(), client.proxy(), client.protocols(), client.connectionSpecs(), client.proxySelector());
这儿出现了SSLSocketFactory 对象,如果url是https则sslSocketFactory有值。如果url是http则sslSocketFactory等于null.所以如果url是https则使用http2.0或spdy协议。如果url是http则使用http1.1协议。
五,SSLSocket的使用
当使用https时,route.address().sslSocketFactory() != null返回值是true,则会调用connectTls方法。
connectTls方法源码是:
private void connectTls(int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { Address address = route.address(); SSLSocketFactory sslSocketFactory = address.sslSocketFactory(); boolean success = false; SSLSocket sslSocket = null; try { // 创建SSLSocket对象。 sslSocket = (SSLSocket) sslSocketFactory.createSocket( rawSocket, address.url().host(), address.url().port(), true /* autoClose */); // Configure the socket's ciphers, TLS versions, and extensions. ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket); if (connectionSpec.supportsTlsExtensions()) { Platform.get().configureTlsExtensions( sslSocket, address.url().host(), address.protocols()); } // Force handshake. This can throw! sslSocket.startHandshake(); Handshake unverifiedHandshake = Handshake.get(sslSocket.getSession()); // Verify that the socket's certificates are acceptable for the target host. if (!address.hostnameVerifier().verify(address.url().host(), sslSocket.getSession())) { X509Certificate cert = (X509Certificate) unverifiedHandshake.peerCertificates().get(0); throw new SSLPeerUnverifiedException("Hostname " + address.url().host() + " not verified:" + "\n certificate: " + CertificatePinner.pin(cert) + "\n DN: " + cert.getSubjectDN().getName() + "\n subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert)); } // Check that the certificate pinner is satisfied by the certificates presented. address.certificatePinner().check(address.url().host(), unverifiedHandshake.peerCertificates()); // Success! Save the handshake and the ALPN protocol. String maybeProtocol = connectionSpec.supportsTlsExtensions() ? Platform.get().getSelectedProtocol(sslSocket) : null; socket = sslSocket;//给socket字段重新赋值。 source = Okio.buffer(Okio.source(socket)); sink = Okio.buffer(Okio.sink(socket)); handshake = unverifiedHandshake; protocol = maybeProtocol != null ? Protocol.get(maybeProtocol) : Protocol.HTTP_1_1; success = true; } catch (AssertionError e) { if (Util.isAndroidGetsocknameError(e)) throw new IOException(e); throw e; } finally { if (sslSocket != null) { Platform.get().afterHandshake(sslSocket); } if (!success) { closeQuietly(sslSocket); } } }
ssl的作用是对网络请求进行加密,让请求更安全。
- OKHttp原码分析(六)之RealConnection
- Okhttp之RealConnection建立链接简单分析
- OKHttp原码分析(五)之Interceptor
- OKHttp原码分析(七)之HttpStream
- OKHttp原码分析(一)
- OKHttp原码分析(四)之getResponseWithInterceptorChain方法
- OKHttp原码分析(八)之必须明白的几个问题
- OkHttp之BridgeInterceptor简单分析
- Okhttp之CacheInterceptor简单分析
- OkHttp之ConnectInterceptor简单分析
- OkHttp实现分析之Websocket
- Okhttp之CallServerInterceptor简单分析
- OkHttp实现分析之Websocket
- webrtc原码分析
- recommenderjob原码分析
- atoi原码分析
- OkHttp源码分析之基本框架1
- OkHttp源码分析之基本框架2
- js 面向对象组件开发参考2
- CSDN代码粘贴
- opencv实现摄像头实时人脸检测
- mysql-5.7.18免安装版配置
- APP store提交出现不能完成的异常
- OKHttp原码分析(六)之RealConnection
- 【开发环境】Source_Insight3.5安装步骤
- vim C++开发环境插件安装详解
- Python:批量编写图片下载程序
- 结算备付金
- 矩阵逆时针旋转90度
- Handler looper meessage messagequeue 之间的关系
- Mysql
- MyEclipse 2016 破解详细过程