Http/2,okhttp等摘要

多路复用

多路复用,代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。 HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制,如下图,红色圈出来的请求就因域名链接数已超过限制,而被挂起等待了一段时间:

  • HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
头部压缩

HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http/2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。

  • 为了减少这块的资源消耗并提升性能, HTTP/2对这些首部采取了压缩策略:
    HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
    首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
    每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
    例如:下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销。

http/2特性

okHttp 链接复用

okhttp简析

那么到底是如何判断一个RealConnection是否可以让StreamAllocation使用呢?其实一个链接能否复用的条件我们能想到无外乎地址一样、端口一样、一条链接线路的负载不超过指定负载数等等这些条件。Okhttp对复用条件做了更多的限制,详见isEligible代码:

public boolean isEligible(Address address, @Nullable Route route) {
    //1、负载超过指定最大负载,不可复用 
    if (allocations.size() >= allocationLimit || noNewStreams) return false;

    //2、Address对象的非主机部分不相等,不可复用 
    if (!Internal.instance.equalsNonHost(this.route.address(), address)) return false;

    //3、非主机部分不相等,不可复用 
 if(address.url().host().equals(this.route().address().url().host())) {
     //这个链接完美的匹配
      return true; // This connection is a perfect match.
    }

    //
    // https://hpbn.co/optimizing-application-delivery/#eliminate-domain-sharding
    // https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/

    // 4. This connection must be HTTP/2.
    if (http2Connection == null) return false;

    // The routes must share an IP address. This requires us to have a DNS address for both
    // hosts, which only happens after route planning. We can't coalesce connections that use a
    // proxy, since proxies don't tell us the origin server's IP address.
    //5
    if (route == null) return false;
    //6
    if (route.proxy().type() != Proxy.Type.DIRECT) return false;
    //7
    if (this.route.proxy().type() != Proxy.Type.DIRECT) return false;
    //8
    if (!this.route.socketAddress().equals(route.socketAddress())) return false;

    // 9
    if (route.address().hostnameVerifier() != OkHostnameVerifier.INSTANCE) return false;
    if (!supportsUrl(address.url())) return false;

    // 10. Certificate pinning must match the host.
    try {
      address.certificatePinner().check(address.url().host(), handshake().peerCertificates());
    } catch (SSLPeerUnverifiedException e) {
      return false;
    }
    //最终可以复用
    return true;
  }

猜你喜欢

转载自blog.csdn.net/shaoyangtangsong/article/details/87784841