OKHTTP分享一框架流程

TCP/IP五层模型

分层(由上至下)作用代表协议
应用层定义报文类型、字段语义 等HTTP、SMTP等
传输层负责进程之间的通信TCP、UDP
网络层负责子网之间的通信、路由寻址(网络地址)IP
链路层定义数据的分组格式、MAC寻址(网卡寻址)
物理层将数据编码为用0、1标识的比特流

- 下层为上层提供服务
- 在发送端,下层封装上层的数据;在接收端,上层解封装下层的数据

这里写图片描述

TCP和UDP

TCP:面向连接、可靠的传输方式;3次招手+4次挥手;慢
UDP:不面向连接、不可靠;快

HTTP概述

  • 定义了WEB服务器和WEB客户端(浏览器)之间的交互方式
  • 使用TCP作为运输层支撑协议
  • 无状态协议,即服务器不保存客户端的任何信息
  • 1.0及1.0之前为非持续连接;1.1及之后为持续连接

Blockquote
非持续连接:为每一个请求的对象建立一个全新的连接,每个连接都有打开-关闭动作;
持续连接:连接持续打开一段时间,多个对象可复用同一条连接

HTTP报文结构

请求报文

这里写图片描述

响应报文

这里写图片描述

Cookie技术

作用:识别和跟踪用户
实现:
1) 客户端首次访问服务器,响应报文首部行包含Set-cookie:1678
2) 客户端将cookie信息保存在自己的cookie文件中
3) 客户端再次向服务器发送请求,请求报文首部行添加Cookie:1678
4) 服务器识别cookie,跟踪和记录客户端访问的顺序及时间等

代理服务器

这里写图片描述
作用:
1)提高访问速度
2)隐藏真实IP
3)过滤用户

代理协议:HTTP、SOCKS

条件Get

作用:避免服务器响应内容过时和节省带宽
实现:
1)客户端向服务器发送请求
GET /a.html HTTP/1.1
2)服务器返回:
Last-Modified: Thu, 22 Nov 2011 21:00:51 GMT
3)客户端下次请求同一对象:
GET /a.html HTTP/1.1
Host: www.hongchangfirst.com
If-Modified-Since: Thu, 22 Nov 2011 21:00:51 GMT
4)如果有更新,返回
HTTP/1.1 200 OK
Server: hongchangfirst server
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 28 Nov 2011 21:00:51 GMT
Content-Length: 14
<...实体体...>
如果未更新,返回(而不返回实体体)
HTTP/1.1 304 Not Modified

OkHttp用法

1)构建OkHttpClient
2)构建Request
3)将得到的Request封装为Call,调用Call的enqueue/execute方法
4)在Callback中处理返回的Response

OkHttpClient mOkHttpClient = new OkHttpClient();
//RequestBody requestBody = new FormBody.Builder().add("k1", "v1").add("k2", "v2").build();
Request request = new Request.Builder().url(url).post(requestBody).build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        MyLogUtil.d(TAG, "get, onFailure");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        try {
            String result = response.body().string();
            MyLogUtil.d(TAG, "get, response=" + result);
        } catch (Exception e){
            e.printStackTrace();
            MyLogUtil.d(TAG, "get, e=", e);
        } finally {
            if (response != null) {
                response.close();
            }
        }

    }
});

主要类介绍

OkHttpClient

  • 可指定缓存路径
    java
    public Builder cache(@Nullable Cache cache) {
    this.cache = cache;
    this.internalCache = null;
    return this;
    }
  • 指定代理服务器

     public Builder proxy(@Nullable Proxy proxy) {
      this.proxy = proxy;
      return this;
    }
  • 指定读、写以及连接超时时间

  • 将Request封装为Call

    @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
    }

    Request

  • HTTP中“请求”的描述

  • 封装了Url、头部、实体体、方法类型
    java
    public final class Request {
    final HttpUrl url;
    final String method;
    final Headers headers;
    final @Nullable RequestBody body;
    final Object tag;
    ...
    }

Call/RealCall

  • Http中“任务”的描述
  • 提供了同步(excute)和异步(enqueue)两种执行方式
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

Dispatcher

  • 将“请求”交给所维护的线程池执行
  • 任务调度
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

AsyncCall

  • RealCall的内部类,每个AsyncCall唯一对应一个RealCall
  • 实现了Runnable,在run()中回调自己的execute()方法
  • 通过getResponseWithInterceptorChain()拿到Response
@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

Response

  • Http中“响应”的描述
  • 封装了状态码、响应头以及实体体(ResponseBody)
  • networkResponse、cacheResponse
public final class Response implements Closeable {
  final Request request;
  final Protocol protocol;
  final int code;
  final String message;
  final @Nullable Handshake handshake;
  final Headers headers;
  final @Nullable ResponseBody body;
  final @Nullable Response networkResponse;
  final @Nullable Response cacheResponse;
  ...
 }

拦截器链-Interceptor.Chain

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }
  • 依次构建Interceptor对象,并依次放入ArrayList中
  • 调用Interceptor.Chain的proceed方法,使interceptors依次工作
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
      ...
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    ...
}
  • 创建下一个拦截链。传入index + 1使得下一个拦截器链只能从下一个拦截器开始访问
  • 执行索引为index的拦截器的intercept方法,并将下一个拦截器链传入该方法

    拦截器Interceptor

  • 在发起请求前对request进行处理
  • 调用下一个拦截器,获取response
  • 对response进行处理,返回给上一个拦截器
执行顺序及作用概述
  • RetryAndFollowUpInterceptor:失败重连、连接复用
  • BridgeInterceptor:设置其他报头,如User-Agent,Host,Keep-alive;添加cookie;设置gzip压缩,并在接收到内容后进行解压
  • CacheInterceptor:决定是请求服务器还是返回cache;对cache进行增删查改
  • ConnectIntercetot:为当前请求找到一条连接,可能复用也可能重新创建
  • CallServerInterceptor:向服务器发起请求,并读取服务器响应

流程框架

这里写图片描述

任务调度

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

如果满足条件:

  • 当前请求数小于最大请求数(64)
  • 对单一host的请求小于阈值(5)

将该任务插入正在执行任务队列(runningAsyncCalls),并执行对应任务。如果不满足则将其放入待执行队列(readyAsyncCalls)。

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }
  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }
  • 空闲出多余线程,调用promoteCalls调用待执行的任务
  • 如果当前整个线程池都空闲下来,执行空闲通知回调线程(idleCallback)

    private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
    
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }
    
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
    }
  • 当线程池有空闲时,从readyAsyncCalls取出“适量”的任务加入到runningAsyncCalls,并通过线程池执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值