HTTP 2.0与OkHttp

HTTP 2.0是对1.x的扩展而非替代,之所以是“2.0”,是因为它改变了客户端与服务器之间交换数据的方式。HTTP 2.0增加了新的二进制分帧数据层,而这一层并不兼容之前的HTTP 1.x服务器及客户端——是谓2.0。
 在正式介绍HTTP 2.0之前,我们需要先了解几个概念。

  • 流,已建立的连接上的双向字节流。
  • 消息,与逻辑消息(RequestResponse)对应的完整的一系列数据帧。
  • 帧,HTTP 2.0通信的最小单位,如Header帧(存储的是Header)、DATA帧(存储的是发送的内容或者内容的一部分)。
1、HTTP 2.0简介

 总所周知,HTTP 1.x拥有队首阻塞、不支持多路复用、Header无法压缩等诸多缺点。尽管针对这些缺点也提出了很多解决方案,如长连接、连接与合并请求、HTTP管道等,但都治标不治本,直到HTTP 2.0的出现,它新增的以下设计从根本上解决了HTTP 1.x所面临的诸多问题。

  • 二进制分帧层,是HTTP 2.0性能增强的核心,改变了客户端与服务器之间交互数据的方式,将传输的信息(HeaderBody等)分割为更小的消息和帧,并采用二进制格式的编码。
  • 并行请求与响应,客户端及服务器可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把这些消息组合起来。
  • 请求优先级(0表示最高优先级、 2 31 2^{31} 231-1表示最低优先级),每个流可以携带一个优先值,有了这个优先值,客户端及服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。但优先级的处理需要慎重,否则有可能会引入队首阻塞问题。
  • 单TCP连接HTTP 2.0可以让所有数据流共用一个连接,从而更有效的使用TCP连接
  • 流量控制,控制每个流占用的资源,与TCP的流量控制实现是一模一样的。
  • 服务器推送HTTP 2.0可以对一个客户端请求发送多个响应,即除了最初请求响应外,服务器还可以额外的向客户端推送资源,而无需客户端明确地请求。
  • 首部(Header)压缩HTTP 2.0会在客户端及服务器使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不会再通过每次请求和响应发送。首部表在连接存续期间始终存在,由客户端及服务器共同渐进的更新。每个新的首部键-值对要么追加到当前表的末尾,要么替换表中的值。

 虽然HTTP 2.0解决了1.x中的诸多问题,但它也存在以下问题。

  • 虽然消除了HTTP队首阻塞现象,但TCP层次上仍然存在队首阻塞现象。要想彻底解决这个问题,就需要彻底抛弃TCP,自己来定义协议。可以参考谷歌的QUIC
  • 如果TCP窗口缩放被禁用,那宽带延迟积效应可能会限制连接的吞吐量。
  • 丢包时,TCP拥塞窗口会缩小。
2、二进制分帧简介

HTTP 2.0的根本改进还是新增的二进制分帧层。与HTTP 1.x使用换行符分割纯文本不同,二进制分帧层更加简介,通过代码处理起来更简单也更有效。
在这里插入图片描述

图片来自HTTP/2 简介

 建立了HTTP 2.0连接后,客户端与服务器会通过交换帧来通信,帧也是基于这个新协议通信的最小单位。所有帧都共享一个8字节的首部,其中包括帧的长度、类型、标志,还有一个保留位和一个31位的流标识符。
在这里插入图片描述

共有的8字节帧首部
  • 16位的长度前缀意味着一帧大约可以携带64KB数据,不包括8字节首部
  • 8位的类型字段决定如何解释帧其余部分的内容
  • 8位的标志字段允许不同的帧类型定义特定于帧的消息标志
  • 1位的保留字段始终置为0
  • 31位的流标识符唯一标识HTTP 2.0的流

HTTP 2.0规定了以下的帧类型。

  • DATA,用于传输HTTP消息体
  • HEADERS,用于传输关于流的额外的首部字段(Header
  • PRIORITY,用于指定或者重新指定流的优先级
  • RST_STREAM,用于通知流的非正常终止
  • SETTINGS,用于通知两端通信方式的配置数据
  • PUSH_PROMISE,用于发出创建流和服务器引用资源的要约
  • PING,用于计算往返时间,执行“活性”检查
  • GOAWAY,用于通知客户端/服务器停止在当前连接中创建流
  • WINDOW_UPDATE,用于针对个别流或者个别连接实现流量控制
  • CONTINUATION,用于继续一系列首部块片段
2.1、HEADER帧

 在发送应用数据之前,必须创建一个新流并随之发送相应的元数据,比如流的优先级、HTTP首部等。HTTP 2.0协议规定客户端和服务器都可以发起新流,因此有以下两种可能。

  • 客户端通过发送HEADERS帧来发起新流,这个帧里包含带有新流ID的公用首部、可选的31位优先值,以及一组HTTP键值对首部
  • 服务器通过发送PUSH_PROMISE帧来发起推送流,这个帧与HEADER帧等效,但它包含“要约流ID”,没有优先值

在这里插入图片描述

带优先值得HEADERS帧
2.2、DATA帧

 应用数据可以分为多个DATA帧,最后一帧要翻转帧首部的END_STREAM字段。
在这里插入图片描述

DATA帧

 数据净荷不会被另行编码或压缩。DATA帧的编码方式取决于应用或者服务器,纯文本、gzip压缩、图片或者视频压缩格式都可以。整个帧由公用的8字节首部及HTTP净荷组成。
 从技术上说,DATA帧的长度字段决定了每帧的数据净荷最多可达 2 31 2^{31} 231-1(65535)字节。可是,为了减少队首阻塞,HTTP 2.0标准要求DATA帧不能超过 2 14 − 1 2^{14}-1 2141(16383)字节。长度超过这个阀值的数据,就得分帧发送。

3、HTTP 2.0在OKHttp中的应用

HTTP 2.0是通过RealConnectionstartHttp2方法开启的,在该方法中会创建一个Http2Connection对象,然后调用Http2Connectionstart方法。

  private void startHttp2(int pingIntervalMillis) throws IOException {
   
    socket.setSoTimeout(0); // HTTP/2 connection timeouts are set per-stream.
    //创建Http2Connection对象
    http2Connection = new Http2Connection.Builder(true)
        .socket(socket, route.address().url().host(), source, sink)
        .listener(this)
        .pingIntervalMillis(pingIntervalMillis)
        .build();
    //开启HTTP 2.0
    http2Connection.start();
  }

 在start方法中会首先给服务器发送一个字符串PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n来进行协议的最终确定,并用于建立 HTTP/2 连接的初始设置。然后给服务器发送一个SETTINGS类型的Header帧,该帧主要是将客户端每一帧的最大容量、Header表的大小、是否开启推送等信息告诉给服务器。如果Window的大小发生改变,就还需要更新Window的大小(HTTP 2.0的默认窗口大小为64KB,而客户端则需要将该大小改为16M,从而避免频繁的更新)。最后开启一个子线程来读取从服务器返回的数据。

  public void start() throws IOException {
   
    start(true);
  }
  void start(boolean sendConnectionPreface) throws IOException {
   
    if (sendConnectionPreface) {
   
      //发送一个字符串PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n来进行协议的最终确定,即序言帧
      writer.connectionPreface();
      //告诉服务器本地的配置信息
      writer.settings(okHttpSettings);
      //okHttpSetting中Window的大小是设置为16M
      int windowSize = okHttpSettings.getInitialWindowSize();
      //默认是64kb,但如果在客户端则需要重新设置为16M
      if (windowSize != Settings.DEFAULT_INITIAL_WINDOW_SIZE) {
   
        //更新窗口大小
        writer.windowUpdate(0, windowSize - Settings.DEFAULT_INITIAL_WINDOW_SIZE);
      }
    }
    //子线程监听服务器返回的消息
    new Thread(readerRunnable).start(); // Not a daemon thread.
  
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值