打开与目标服务器的连接,然后继续执行下一个拦截器
object ConnectInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val request = realChain.request()
val transmitter = realChain.transmitter()
// 请求不为GET请求
val doExtensiveHealthChecks = request.method != "GET"
// 实例化交换器
val exchange = transmitter.newExchange(chain, doExtensiveHealthChecks)
return realChain.proceed(request, transmitter, exchange)
}
}
internal fun newExchange(chain: Interceptor.Chain, doExtensiveHealthChecks: Boolean): Exchange {
synchronized(connectionPool) {
check(!noMoreExchanges) { "released" }
check(exchange == null) {
"cannot make a new request because the previous response is still open: " +
"please call response.close()"
}
}
// exchangeFinder在RetryAndFollowUpInterceptor中实例化,实例化交换编码器
val codec = exchangeFinder!!.find(client, chain, doExtensiveHealthChecks)
// 默认eventListener中的方法没有实现
val result = Exchange(this, call, eventListener, exchangeFinder!!, codec)
synchronized(connectionPool) {
this.exchange = result
// 请求是否发送完成
this.exchangeRequestDone = false
// 响应是否接收完成
this.exchangeResponseDone = false
return result
}
}
fun find(
client: OkHttpClient,
chain: Interceptor.Chain,
doExtensiveHealthChecks: Boolean
): ExchangeCodec {
val connectTimeout = chain.connectTimeoutMillis()
val readTimeout = chain.readTimeoutMillis()
val writeTimeout = chain.writeTimeoutMillis()
val pingIntervalMillis = client.pingIntervalMillis
val connectionRetryEnabled = client.retryOnConnectionFailure
try {
val resultConnection = findHealthyConnection(
connectTimeout = connectTimeout,
readTimeout = readTimeout,
writeTimeout = writeTimeout,
pingIntervalMillis = pingIntervalMillis,
connectionRetryEnabled = connectionRetryEnabled,
doExtensiveHealthChecks = doExtensiveHealthChecks
)
return resultConnection.newCodec(client, chain)
} catch (e: RouteException) {
trackFailure()
throw e
} catch (e: IOException) {
trackFailure()
throw RouteException(e)
}
}
private fun findHealthyConnection(
connectTimeout: Int,
readTimeout: Int,
writeTimeout: Int,
pingIntervalMillis: Int,
connectionRetryEnabled: Boolean,
doExtensiveHealthChecks: Boolean
): RealConnection {
while (true) {
val candidate = findConnection(
connectTimeout = connectTimeout,
readTimeout = readTimeout,
writeTimeout = writeTimeout,
pingIntervalMillis = pingIntervalMillis,
connectionRetryEnabled = connectionRetryEnabled
)
// 如果是一个新连接,跳过检查连接的健康状态
synchronized(connectionPool) {
if (candidate.successCount == 0) {
return candidate
}
}
// 检查连接的健康状态,如果不健康,重新寻找连接
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
candidate.noNewExchanges()
continue
}
return candidate
}
}
private fun findConnection(
connectTimeout: Int,
readTimeout: Int,
writeTimeout: Int,
pingIntervalMillis: Int,
connectionRetryEnabled: Boolean
): RealConnection {
var foundPooledConnection = false
var result: RealConnection? = null
var selectedRoute: Route? = null
var releasedConnection: RealConnection?
val toClose: Socket?
synchronized(connectionPool) {
if (transmitter.isCanceled) throw IOException("Canceled")
hasStreamFailure = false // 这是新尝试
// 已使用的连接是否健康
releasedConnection = transmitter.connection
toClose = if (transmitter.connection != null && transmitter.connection!!.noNewExchanges) {
// 从连接池清除连接
transmitter.releaseConnectionNoEvents()
} else {
null
}
if (transmitter.connection != null) {
// 已使用的连接是健康的
result = transmitter.connection
releasedConnection = null
}
if (result == null) {
// 尝试从连接池获取连接
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
foundPooledConnection = true
result = transmitter.connection
} else if (nextRouteToTry != null) {
// 取下一个路由
selectedRoute = nextRouteToTry
nextRouteToTry = null
} else if (retryCurrentRoute()) {
// 现在路由可用
selectedRoute = transmitter.connection!!.route()
}
}
}
toClose?.closeQuietly()
// 已使用连接不可用
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection!!)
}
// 从连接池获取连接
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result!!)
}
if (result != null) {
// 已使用连接或连接池中连接
return result!!
}
// 路由选择器
var newRouteSelection = false
if (selectedRoute == null && (routeSelection == null || !routeSelection!!.hasNext())) {
newRouteSelection = true
routeSelection = routeSelector.next()
}
var routes: List<Route>? = null
synchronized(connectionPool) {
if (transmitter.isCanceled) throw IOException("Canceled")
if (newRouteSelection) {
// 利用路由从连接池获取连接
routes = routeSelection!!.routes
if (connectionPool.transmitterAcquirePooledConnection(
address, transmitter, routes, false)) {
foundPooledConnection = true
result = transmitter.connection
}
}
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection!!.next()
}
// 创建连接并立即将其分配。这使得异步cancel()可以中断我们即
// 将进行的握手。
result = RealConnection(connectionPool, selectedRoute!!)
connectingConnection = result
}
}
// 我们第二次获取连接成功
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result!!)
return result!!
}
// TCP + TLS 握手
result!!.connect(
connectTimeout,
readTimeout,
writeTimeout,
pingIntervalMillis,
connectionRetryEnabled,
call,
eventListener
)
// 在失败列表中去除路由
connectionPool.routeDatabase.connected(result!!.route())
var socket: Socket? = null
synchronized(connectionPool) {
connectingConnection = null
// 上次尝试连接合并,只有在我们尝试多个并发连接到同一主机时才会发生。
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
// 关闭我们创建的连接并返回池化连接。
result!!.noNewExchanges = true
socket = result!!.socket()
result = transmitter.connection
// 我们可以获得立即不健康的合并连接。在这种情况下,我们将重试我们刚刚
// 成功连接的路线。
nextRouteToTry = selectedRoute
} else {
// 将连接放入连接池
connectionPool.put(result!!)
transmitter.acquireConnectionNoEvents(result!!)
}
}
socket?.closeQuietly()
eventListener.connectionAcquired(call, result!!)
return result!!
}
fun transmitterAcquirePooledConnection(
address: Address,
transmitter: Transmitter,
routes: List<Route>?,
requireMultiplexed: Boolean
): Boolean {
assert(Thread.holdsLock(this))
for (connection in connections) {
// 接收但不是HTTP2连接
if (requireMultiplexed && !connection.isMultiplexed) continue
// 如果此连接可以将流发送到“address”,则返回true。
if (!connection.isEligible(address, routes)) continue
// 将连接添加到执行器中
transmitter.acquireConnectionNoEvents(connection)
return true
}
return false
}
fun connect(
connectTimeout: Int,
readTimeout: Int,
writeTimeout: Int,
pingIntervalMillis: Int,
connectionRetryEnabled: Boolean,
call: Call,
eventListener: EventListener
) {
check(protocol == null) { "already connected" }
var routeException: RouteException? = null
val connectionSpecs = route.address.connectionSpecs
val connectionSpecSelector = ConnectionSpecSelector(connectionSpecs)
if (route.address.sslSocketFactory == null) {
// HTTP协议
if (ConnectionSpec.CLEARTEXT !in connectionSpecs) {
throw RouteException(UnknownServiceException(
"CLEARTEXT communication not enabled for client"))
}
val host = route.address.url.host
if (!Platform.get().isCleartextTrafficPermitted(host)) {
throw RouteException(UnknownServiceException(
"CLEARTEXT communication to $host not permitted by network security policy"))
}
} else {
if (Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols) {
throw RouteException(UnknownServiceException(
"H2_PRIOR_KNOWLEDGE cannot be used with HTTPS"))
}
}
while (true) {
try {
// 如果此路由通过HTTP代理隧道HTTPS,则返回true。
if (route.requiresTunnel()) {
// 使用代理通道创建HTTPS连接,包括创建rawSocket和tunnel
connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)
if (rawSocket == null) {
// 我们无法连接隧道,但正确关闭了我们的资源。
break
}
} else {
// 创建HTTP或HTTPS连接
connectSocket(connectTimeout, readTimeout, call, eventListener)
}
// 根据协议创建socket
establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener)
eventListener.connectEnd(call, route.socketAddress, route.proxy, protocol)
break
} catch (e: IOException) {
socket?.closeQuietly()
rawSocket?.closeQuietly()
socket = null
rawSocket = null
source = null
sink = null
handshake = null
protocol = null
http2Connection = null
eventListener.connectFailed(call, route.socketAddress, route.proxy, null, e)
if (routeException == null) {
routeException = RouteException(e)
} else {
routeException.addConnectException(e)
}
if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(e)) {
throw routeException
}
}
}
if (route.requiresTunnel() && rawSocket == null) {
throw RouteException(ProtocolException(
"Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS"))
}
val http2Connection = this.http2Connection
if (http2Connection != null) {
synchronized(connectionPool) {
// HTTP2缓冲区限制
allocationLimit = http2Connection.maxConcurrentStreams()
}
}
}
internal fun newCodec(client: OkHttpClient, chain: Interceptor.Chain): ExchangeCodec {
val socket = this.socket!!
val source = this.source!!
val sink = this.sink!!
val http2Connection = this.http2Connection
return if (http2Connection != null) {
// HTTP2交换编解码器
Http2ExchangeCodec(client, this, chain, http2Connection)
} else {
// HTTP1交换编解码器
socket.soTimeout = chain.readTimeoutMillis()
source.timeout().timeout(chain.readTimeoutMillis().toLong(), MILLISECONDS)
sink.timeout().timeout(chain.writeTimeoutMillis().toLong(), MILLISECONDS)
Http1ExchangeCodec(client, this, source, sink)
}
}
总结

连接拦截器的主要工作是获取交换器对象,获取的过程中包含了获取连接的操作(复用当前连接,连接池中获取或新建连接)
连接池是OkHttpClient中的对象,默认连接池中的连接的有效时间为5分钟,最大连接数为5个,连接同时可以被1个执行器使用。