OkHttp源码解析

1.OkHttp使用方法

okhttp是一个第三方类库,用于android中请求网络。

implementation("com.squareup.okhttp3:okhttp:4.9.0")
    val url = "https://www.baidu.com/"

    val client = OkHttpClient()
    val request : Request = Request.Builder()
        .url(url)
        .build()

    client.newCall(request)
        .enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {

            }
            override fun onResponse(call: Call, response: Response) {
                println("Response status code: ${response.code}")//这里输出了状态码
            }
        })

2.OkHttp请求流程

2.1 从请求处理开始分析

无论在使用OkHttp进行什么请求的时候都会创建OkHttpClient对象并调用他的 newCall() 方法

1.newCall()

 override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

返回了一个RealCall对象,所以也就意味着我们使用OkHttpClient对象调用的execute()操作实际上是RealCall的execute()操作,那我们就来看RealCall的execute()方法

2.RealCall的execute()

override fun execute(): Response {
	 // check()是kotlin特有的一个方法,他本质上就是一个if,
     // 但是当他的判断语句是false的话,
     // 他就会抛出一个IllegalStateException异常,异常的内容就是后面的语句
     // executed是一个布尔值,他的作用就是判断是不是执行过了,
     // 如果执行过了还执行了这个方法的话就抛异常
    check(executed.compareAndSet(false, true)) { "Already Executed" }
	
    timeout.enter()
    callStart()
    try {
      //调用了client.dispatcher,是Dispatcher类的一个对象
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
      client.dispatcher.finished(this)
    }
  }

2.2 Dispatcher任务调度

Dispatcher类,有如下成员变量定义:

// 最大并发请求数
  var maxRequests = 64
// 每个主机的最大请求数
  var maxRequestsPerHost = 5
// 消费者线程
  val executorService: ExecutorService
// 将要运行的异步请求队列
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的异步请求队队列
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的同步请求队列
  private val runningSyncCalls = ArrayDeque<RealCall>()

Dispatcher的构造方法

// 主构造方法,没写具体实现
class Dispatcher constructor() {}

constructor(executorService: ExecutorService) : this() {
    this.executorServiceOrNull = executorService
}

传进来的executorService传给了executorServiceOrNull
executorServiceOrNull

// executorServiceOrNull这个应该是因为kotlin的空安全检查特性而定义的,
//本质上就是executorService
  private var executorServiceOrNull: ExecutorService? = null

  @get:Synchronized
  @get:JvmName("executorService") val executorService: ExecutorService
    get() {
      if (executorServiceOrNull == null) {
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
      return executorServiceOrNull!!
    }

我们可以看到executorService的set方法,就是创建了一个线程池。再结合他有两个构造器就知道:如果没有给Dispatcher传入一个线程池他就会自己创建一个线程池。这个线程池适合执行大量且耗时较少的任务。

enqueue()方法

  internal fun enqueue(call: AsyncCall) {
    synchronized(this) {
      readyAsyncCalls.add(call)
//来一个请求就把他添加到就绪请求队列中去
      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
      //然后就来判断forWebSocket这个属性
      //OkHttp还可以进行WebSocket通信,而这个属性就是为WebSocket通信准备的。
      if (!call.call.forWebSocket) {
        val existingCall = findExistingCallWithHost(call.host)
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
      }
    }
    promoteAndExecute()
  }

在RealCall的newRealCall()方法这块,这个方法传入的参数中有一个Boolean值名字就叫forWebSocket。

companion object {
    fun newRealCall(
        client: OkHttpClient,
        originalRequest: Request,
        forWebSocket: Boolean
    ): RealCall {
        // Safely publish the Call instance to the EventListener.
        return RealCall(client, originalRequest, forWebSocket).apply {
            transmitter = Transmitter(client, this)
        }
    }
}

promoteAndExecute()方法:

 private fun promoteAndExecute(): Boolean {
  // 这个和check也一样,只不过抛出的是AssertionError异常
    this.assertThreadDoesntHoldLock()

// mutableListOf是kotlin里面的可变list集合
    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning: Boolean
    synchronized(this) {
      val i = readyAsyncCalls.iterator()
      	//首先将已经就绪队列遍历一遍
      while (i.hasNext()) {
        val asyncCall = i.next()
        
	//判断正在运行的数量是不是大于定义的最大请求数
	//如果大于的话直接退出循环
        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
        
    //如果不大于,则判断这个主机请求数是不是大于定义的每个主机最大请求数
    //如果大于就跳过这个请求换下一个请求
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
        i.remove()
        asyncCall.callsPerHost.incrementAndGet()        
	//不大于就把它调入正在运行的请求队列里面,直到遍历完成。
        executableCalls.add(asyncCall)
        runningAsyncCalls.add(asyncCall)
      }
      //然后判断还有没有正在运行的请求,如果有就isRunning置true。
      isRunning = runningCallsCount() > 0
    }

//接着再取出executableCalls里的每一个元素,然后执行executteOn()方法。
    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }

    return isRunning
  }

AsyncCall的executeOn()方法:

    fun executeOn(executorService: ExecutorService) {
      client.dispatcher.assertThreadDoesntHoldLock()

      var success = false
      try {
      //如果成功执行就将success置true
        executorService.execute(this)
        success = true
      } catch (e: RejectedExecutionException) {
      //如果不成功,则抛异常并返回给responseCallback的onFailure()方法。
        val ioException = InterruptedIOException("executor rejected")
        ioException.initCause(e)
        noMoreExchanges(ioException)
        responseCallback.onFailure(this@RealCall, ioException)
      } finally {
        if (!success) {
        //如果没有成功执行也就是success为false,
        //那么在finally中就会执行client.dispatcher.finished()方法:
          client.dispatcher.finished(this) // This call is no longer running!
        }
      }
    }
 

这段代码就是在执行线程池中的线程

  internal fun finished(call: AsyncCall) {
    call.callsPerHost.decrementAndGet()
    finished(runningAsyncCalls, call)
  }

这个方法先将传入的AsyncCall的callsPerHost给减1,然后再调用了finished()方法,

  private fun <T> finished(calls: Deque<T>, call: T) {
    val idleCallback: Runnable?
    synchronized(this) {
      if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
      idleCallback = this.idleCallback
    }

//promoteAndExecute()方法,他的返回值就是判断当前这个运行队列中还有没有请求
//如果还有就返回true,没有就false。
    val isRunning = promoteAndExecute()
//if,判断isRunning和idleCallback,
//如果当前这个请求还没有执行的话,就调用run()方法执行当前请求。这样每个请求都执行完毕了。
    if (!isRunning && idleCallback != null) {
      idleCallback.run()
    }
  }

run()方法

override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
            var signalledCallback = false
            transmitter.timeoutEnter()
            try {
            //调用了一个getResponseWithInterceptorChain()方法,并返回了response
                val response = getResponseWithInterceptorChain()
                signalledCallback = true
                //并将它返回给了responseCallback.onResponse()方法
                responseCallback.onResponse(this@RealCall, response)
            } catch (e: IOException) {
                if (signalledCallback) {
                    // Do not signal the callback twice!
                    Platform.get().log(INFO, "Callback failure for ${toLoggableString()}", e)
                } else {
                //如果失败了就将结果返回给responseCallback.onFailure()方法
                    responseCallback.onFailure(this@RealCall, e)
                }
            } finally {
            //最后调用client.dispatcher.finished()方法。
                client.dispatcher.finished(this)
            }
      }
}

2.3 Interceptor拦截器

getResponseWithInterceptorChain()方法

@Throws(IOException::class)
  internal fun getResponseWithInterceptorChain(): Response {
    // Build a full stack of interceptors.
    //首先就创建了一大堆的连接器并添加到interceptors集合中。
    val interceptors = mutableListOf<Interceptor>()
    interceptors += client.interceptors
    interceptors += RetryAndFollowUpInterceptor(client)
    interceptors += BridgeInterceptor(client.cookieJar)
    interceptors += CacheInterceptor(client.cache)
    interceptors += ConnectInterceptor
    if (!forWebSocket) {
      interceptors += client.networkInterceptors
    }
    interceptors += CallServerInterceptor(forWebSocket)
    
	//然后创建了一个RealInterceptorChain对象,
    val chain = RealInterceptorChain(
        call = this,
        interceptors = interceptors,
        index = 0,
        exchange = null,
        request = originalRequest,
        connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )

    var calledNoMoreExchanges = false
    try {
    //并调用了他的proceed()方法,
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
        response.closeQuietly()
        throw IOException("Canceled")
      }
      //接着主要目的就是将proceed()返回的response给返回去。
      return response
    } catch (e: IOException) {
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
      if (!calledNoMoreExchanges) {
        noMoreExchanges(null)
      }
    }
  }

RealInterceptorChain的proceed()方法:

  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
    check(index < interceptors.size)
//首先就是一个index,index是RealInterceptorChain构造器中传入的参数,是第四个参数,
//所以我们看getResponseWithInterceptorChain()方法中创建RealInterceptorChain对象时构造器的第四个传入的值为0。
//然后判断index的值是不是大于interceptors的大小,如果大于就抛异常,否则就继续检查

    calls++

    if (exchange != null) {
      check(exchange.finder.sameHostAndPort(request.url)) {
        "network interceptor ${interceptors[index - 1]} must retain the same host and port"
      }
      check(calls == 1) {
        "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
      }
    }

    // Call the next interceptor in the chain.
    //然后再创建RealInterceptorChain对象,此时创建的对象传入的index为此时的index+1
    //然后再调用interceptor的intercept()方法,并返回response。
    val next = copy(index = index + 1, request = request)
    val interceptor = interceptors[index]

    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")

    if (exchange != null) {
      check(index + 1 >= interceptors.size || next.calls == 1) {
        "network interceptor $interceptor must call proceed() exactly once"
      }
    }

    check(response.body != null) { "interceptor $interceptor returned a response with no body" }

    return response
}

2.3 Interceptor源码

OkHttp中Interceptor的实现类有:
ConnectInterceptor:连接拦截器。
CallServerInterceptor:请求服务器拦截器
CacheInterceptor:缓存拦截器
BridgeInterceptor:桥梁拦截器。

其中较为重要的就是ConnectInterceptor和CallServerInterceptor

ConnectInterceptor

这个类主要用来实现网络请求连接。
intercept方法


@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
//先将传入的chain对象造型成了RealInterceptorChain的对象
//然后调用他的request()和transmitter()方法,分别得到当前chain的request和transmitter
    val realChain = chain as RealInterceptorChain
    val request = realChain.request()
    val transmitter = realChain.transmitter()

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    //然后执行了request的method()方法,判断request的类型是不是GET
    //如果是doExtensiveHealthChecks就为false,否则为true
    val doExtensiveHealthChecks = request.method != "GET"
    //接着把doExtensiveHealthChecks传入transmitter的newExchange()方法中去
    val exchange = transmitter.newExchange(chain, doExtensiveHealthChecks)

	//然后再调用了proceed()方法
    return realChain.proceed(request, transmitter, exchange)
}

CallServerInterceptor
这个类是网络请求的本质。它的intercept方法源码如下:
主要是向服务器发送请求数据和接受服务器返回的数据

@Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    val exchange = realChain.exchange()
    val request = realChain.request()
    val requestBody = request.body
    val sentRequestMillis = System.currentTimeMillis()

    // 写入请求头
    exchange.writeRequestHeaders(request)

    var responseHeadersStarted = false
    var responseBuilder: Response.Builder? = null
    // 写入请求体信息
    if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
        // 如果请求上有“expect:100 continue”头
        // 请等待“http/1.1 100 continue”响应,然后再传输请求主体.
        // 如果我们没有得到,返回我们得到的(例如4xx响应),而不传输请求体。
        if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
            exchange.flushRequest()
            responseHeadersStarted = true
            exchange.responseHeadersStart()
            responseBuilder = exchange.readResponseHeaders(true)
        }
        if (responseBuilder == null) {
            if (requestBody.isDuplex()) {
                // 准备一个双工主体,以便应用程序稍后可以发送请求主体。
                exchange.flushRequest()
                val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
                requestBody.writeTo(bufferedRequestBody)
            } else {
                // 如果满足“expect:100 continue”预期,则编写请求正文。
                val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
                requestBody.writeTo(bufferedRequestBody)
                bufferedRequestBody.close()
            }
        } else {
            exchange.noRequestBody()
            if (!exchange.connection()!!.isMultiplexed) {
                // 如果不满足“expect:100 continue”的要求,请防止重用HTTP/1连接。
                // 否则,我们仍然有义务传输请求主体以使连接保持一致状态。
                exchange.noNewExchangesOnConnection()
            }
        }
    } else {
        exchange.noRequestBody()
    }

    // 结束请求
    if (requestBody == null || !requestBody.isDuplex()) {
        exchange.finishRequest()
    }
    if (!responseHeadersStarted) {
        exchange.responseHeadersStart()
    }
    if (responseBuilder == null) {
        responseBuilder = exchange.readResponseHeaders(false)!!
    }
    // 读取响应头信息
    var response = responseBuilder
        .request(request)
        .handshake(exchange.connection()!!.handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build()
    var code = response.code
    if (code == 100) {
        // 服务器发送了一个100继续,即使我们没有请求。
        // 再次尝试读取实际响应
        response = exchange.readResponseHeaders(false)!!
            .request(request)
            .handshake(exchange.connection()!!.handshake())
            .sentRequestAtMillis(sentRequestMillis)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build()
        code = response.code
    }

    exchange.responseHeadersEnd(response)

    // openResponseBody 获取响应体信息
    response = if (forWebSocket && code == 101) {
        // 连接正在升级,但我们需要确保拦截器看到非空的响应主体。
        response.newBuilder()
            .body(EMPTY_RESPONSE)
            .build()
        } else {
            response.newBuilder()
                .body(exchange.openResponseBody(response))
                .build()
        }
        if ("close".equals(response.request.header("Connection"), ignoreCase = true) ||
        "close".equals(response.header("Connection"), ignoreCase = true)) {
            exchange.noNewExchangesOnConnection()
        }
        if ((code == 204 || code == 205) && response.body?.contentLength() ?: -1L > 0L) {
            throw ProtocolException(
                "HTTP $code had non-zero Content-Length: ${response.body?.contentLength()}")
        }
    
    //返回一个响应
    return response
}

2.4 Transmiter

Transmitter类是OkHttp的应用层和网络层的一个桥梁类。
该类的初始化:

class Transmitter(
//构造器中传入了两个参数,一个OkHttpClient,一个Call
    private val client: OkHttpClient,
    private val call: Call
) {
//然后又创建了一个连接池connectionPool,
//还有一个监听器,我们可以通过扩展这个类来监听程序的HTTP的调用数量、大小和持续时间
    private val connectionPool: RealConnectionPool = client.connectionPool.delegate
    private val eventListener: EventListener = client.eventListenerFactory.create(call)
    private val timeout = object : AsyncTimeout() {
        override fun timedOut() {
            cancel()
        }
    }.apply {
        timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
    }

2.5 RealConnection

class RealConnection(
    val connectionPool: RealConnectionPool,
    private val route: Route
) : Http2Connection.Listener(), Connection {

    // 以下字段由connect()初始化,从不重新分配。
    // 底层socket
    private var rawSocket: Socket? = null

    /**
     * 应用层套接字。如果此连接不使用SSL,则可以是[sslsocket]分层在[rawsocket]上,也可以是[rawsocket]本身。
    */
    // 应用层socket
    private var socket: Socket? = null
    // 握手
    private var handshake: Handshake? = null
    //  协议
    private var protocol: Protocol? = null
    // http2的连接
    private var http2Connection: Http2Connection? = null
    // 与服务器交互的输入输出流
    private var source: BufferedSource? = null
    private var sink: BufferedSink? = null

    // 跟踪连接状态下的字段由连接池保护。

    /**
     * 如果为true,则不能在此连接上创建新的交换。一旦是true的,这总是true的。
     * 由[ConnectionPool]监视。
     */
    var noNewExchanges = false

    /**
     * 建立可能由于所选路由而导致的流时出现问题的次数。由[ConnectionPool]保护。
     */
    internal var routeFailureCount = 0

    internal var successCount = 0
    private var refusedStreamCount = 0

    /**
     * 此连接可以承载的最大并发流数。
     * 如果“allocations.size()<allocationlimit”,则可以在此连接上创建新流。     
     */ 
    private var allocationLimit = 1

connect()方法:

fun connect(
    connectTimeout: Int,
    readTimeout: Int,
    writeTimeout: Int,
    pingIntervalMillis: Int,
    connectionRetryEnabled: Boolean,
    call: Call,
    eventListener: EventListener
) {
	//首先检查是否已经建立连接,如果已经建立就抛异常,没有的话就继续
    check(protocol == null) { "already connected" }

    // 线路的选择
    //接着就得到了ConnectionSpecs,然后根据他建立了一个connectionSpecSelector集合
    var routeException: RouteException? = null
    val connectionSpecs = route.address.connectionSpecs
    val connectionSpecSelector = ConnectionSpecSelector(connectionSpecs)

	//接着判断是不是安全连接,也就是ssl连接
	//如果不是的话就判断了一些属性,先确定是不是明文然后再确定主机能不能接受明文操作。
    if (route.address.sslSocketFactory == null) {
        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"))
        }
    }

    //接着就开始连接,判断是不是要进行隧道通信,
    //如果是就调用connectTunnel()建立隧道通信,如果不是就调用connectSocket()建立普通的通信
    while (true) {
        try {
            // 如果要求隧道模式,建立通道连接,通常不是这种
            if (route.requiresTunnel()) {
                connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)
                if (rawSocket == null) {
                    // 我们无法连接隧道,但适当关闭了我们的资源。
                    break
                }
            } else {
                // 一般都走这条逻辑了,实际上很简单就是socket的连接
                connectSocket(connectTimeout, readTimeout, call, eventListener)
            }
            // https的建立
            //通过establishProtocol()建立协议。如果是HTTP/2就设置相关属性。
            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) {
            allocationLimit = http2Connection.maxConcurrentStreams()
        }
    }
}

再来看看具体如何实现
connectSocket()方法

@Throws(IOException::class)
private fun connectSocket(
    connectTimeout: Int,
    readTimeout: Int,
    call: Call,
    eventListener: EventListener
) {
    val proxy = route.proxy
    val address = route.address

    // 根据代理类型选择socket类型是代理还是直连
    // 首先先判断连接类型,如果是直连或者HTTP连接就直连,否则的话走Socket代理
    val rawSocket = when (proxy.type()) {
        Proxy.Type.DIRECT, Proxy.Type.HTTP -> address.socketFactory.createSocket()!!
        else -> Socket(proxy)
    }
    this.rawSocket = rawSocket

	//然后通过eventListener.connectStart()方法创建连接,
	//再设定超时->完成连接->创建用于I/O的source和sink
    eventListener.connectStart(call, route.socketAddress, proxy)
    rawSocket.soTimeout = readTimeout
    try {
        // 连接socket,之所以这样写是因为支持不同的平台
        // 里面实际上是  socket.connect(address, connectTimeout);
        Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)
    } catch (e: ConnectException) {
        throw ConnectException("Failed to connect to ${route.socketAddress}").apply {
            initCause(e)
        }
    }

    // 下面的Try/Catch块是一种避免Android 7.0崩溃的伪黑客方法
    // More details:
    // https://github.com/square/okhttp/issues/3245
    // https://android-review.googlesource.com/#/c/271775/
    try {
        // 得到输入/输出流
        source = rawSocket.source().buffer()
        sink = rawSocket.sink().buffer()
    } catch (npe: NullPointerException) {
        if (npe.message == NPE_THROW_WITH_NULL) {
            throw IOException(npe)
        }
    }
}

connectTunnel()方法

//先创建隧道请求,然后建立socket连接,再发送请求建立隧道。
@Throws(IOException::class)
private fun connectTunnel(
    connectTimeout: Int,
    readTimeout: Int,
    writeTimeout: Int,
    call: Call,
    eventListener: EventListener
) {
    var tunnelRequest: Request = createTunnelRequest()
    val url = tunnelRequest.url
    for (i in 0 until MAX_TUNNEL_ATTEMPTS) {
        connectSocket(connectTimeout, readTimeout, call, eventListener)
        tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url)
            ?: break // 已成功创建隧道。

        // 代理决定在身份验证质询后关闭连接。
        // 我们需要创建一个新的连接,但这次需要使用身份验证凭据。
        rawSocket?.closeQuietly()
        rawSocket = null
        sink = null
        source = null
        eventListener.connectEnd(call, route.socketAddress, route.proxy, null)
    }
}

3.请求流程

同步请求的操作
在这里插入图片描述
异步请求的操作
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值