HTTP2协议

051.HTTP/1.1发展至今遇到的问题
    现代的网络世界随着贷款的增加,延迟并没有显著下降,
    并发连接有限(比如Chrome一个客户端针对一个域名最多只能同时支持6个HTTP连接)
    统一连接同时只能完成一个HTTP事务(即必须等一个请求/响应完了之后才能继续处理下一个请求/响应)
    长肥网络 带宽很大,但是延迟也很高
052.HTTP/1.1为了解决性能问题做过的努力
    Spriting 合并多张小图为一张大图供浏览器JS拼凑使用
    Inlining内联,将图片嵌入到CSS或者HTML文件中,减少网络请求次数
    Concatenation 拼接,将多个体积较小的JS使用webpak等工具打包成1个JS文件,减少网络请求次数
    Sharding分片,将同一个页面的资源分散到不同的页面,提升连接上限
053.HTTP2协议的特点
    HTTP2协议是基于谷歌的SPDY协议的,它拥有以下特点
    。在应用层上修改,基于并充分挖掘TCP的协议性能
    。客户端向Server发送Request,服务器发送响应Response这种基本模型不变
    。老的schema不变,还是http://和https://
    。使用HTTP/1.1的客户端和服务器可以无缝的通过代理方式转移到HTTP/2上
    。不识别HTTP/2的代理服务器可以将请求降级为HTTP/1.1
    。传输的数据量大幅减少,以二进制的方式传输数据,标头压缩
    。多路复用,消息优先级
    。服务器端并发消息推送
054.HTTP/2是不是必须基于TLS/SSL协议?
    。IETF标准不要求必须基于TLS、SSL协议
    。浏览器要求必须基于TLS/SSL协议
    。在TLS层ALPN(Application Layer Protocal Negotiation)扩展做协商,只认识HTTP/1.1的代理服务器不会干扰HTTP/2
    。schema还是http:// 和https://,默认基于80和443端口
    。h2 基于TLS协议运行的HTTP/2被称为h2
    。h2c 直接才TCP协议之上运行的HTTP/2称为h2c
    从HTTP/1.1升级到h2其实是基于ALPN这个扩展来实现的,
    而从HTTP/1.1升级到h2c,其实是和HTTP/1.1升级到WebSocket协议是一样的,步骤如下
    1.客户端传一个头部 
    Connection: Upgrade,HTTP2-Settings
    Upgrade: h2c
    HTTP2-Settings: 438997893ab379
    2.客户端回一个101响应码
    HTTP/1.1 101 SwitchingProtocals
    Connection: Upgrade
    Upgrade: h2c
    3.客户端再发送一个Magic帧,Magic帧的固定格式 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
055.TLS通讯过程
    1.客户端发起一个Client Hello
    2.服务器端回复一个Server Hello,并携带上自己支持的加密算法
    3.服务器端发送一个证书,并发送一个自己已经选择的加密算法
    4.客户端收到证书后,验证证书
    5.服务器端再发送一个Server Hello 这时连接已经建立了
    6.客户端和服务器端都基于加密算法经过非对称加密,都得到一个加密秘钥
    7.接下来所有的数据传输都是基于这个加密秘钥的
056.h2的会话建立过程
    1.客户端发送Client Hello 在请求的ALPN扩展中列出客户端支持的所有应用层协议(是一个列表)
    2.服务器端收到Client Hello 后也在响应的ALPN扩展中将自己选择的协议告知客户端
    3.客户端再发送一个由Magic帧和Settings真共同组成的报文请求,Settings真必须存在,哪怕没有携带任何数据
    这时会话就建立了
057.消息、流、帧之间的关系
    1.一个HTTP请求或响应就称为一个消息,在HTTP/1.1中一条消息是不能再拆分的,消息是数据传输的最小单位
    2.连接Connection,即一个客户端和一个服务器只能建立一个TCP连接,一个连接上包含一个或多个流,流与流之间是并发进行的
    3.数据流Stream,一个双向的数据流,包含一条或者多条消息
    4.数据帧Fream,在HTTP/1.1中没有帧的概念,但是在HTTP2中一个消息可以被拆分成一个或者多个帧(HEADERS帧对应HTTP/1.1的头部 DATAS帧对应的是HTTP/1.1中的包体,帧与消息本质上没有什么关系,他们之间建立的是应用程层上的业务逻辑关系)
    5.传输时无序,接收时组装:在同一个stream中,帧必须是按顺序传输的,但是在不同的stream中,frame可以是无序的 
      例如传输时应该是这样的:stream1(headers)-stream3(headers)-stream3(data)-stream1(data)
      接收端根据streamId来组装数据
058.StreamID
    使用控制帧SETTINGS_MAX_CONCURRENT_STREAMS来控制并发的stream数
    客户端建立的stream流的streamid必须是基数
    服务器端建立的stream流的streamid必须是偶数
    新建立的流的ID必须大于曾经建立过的状态为opened或者reserved的流ID
    在新建立的流上发送帧时,意味着更小的ID为idle状态的流设置为closed状态
    StreamID不能复用,长连接耗尽ID创建新连接,比如当StreamID到达2的31次方时,就必须关闭当前的长连接,重新开启一个长连接
    StreamId为0时,只能用于传输控制帧
059.帧的属性
    0至2的14次方 - 1 所有实现必须可以支持16KB以下的帧
    2的14资方至2的24次方-1 传递16KB到16MB时,必须接收端首先公布自己可以处理此大小,通过SETTINGS_MAX_FRAME_SIZE帧(Identifier)告知
    帧类型
    -DATA 0x0 传递HTTP包体
    -HEADERS 0x1 传递HTTP头部
    -PRIORITY 0x2 指定Stream流的优先级
    -RST-STREAM 0x3 终止Stream流
    -SETTINGS 0x4 修改连接或者Stream的配置
    -PUSH-PROMISE 0x5 服务器端推送请求时描述请求的帧,只能由服务器发送
    -PING 0x6 心跳检测,间距RTT往返时间的功能
    -GOAWAY 0x7 优雅的终止连接或者通知错误
    -WINDOW_UPDATE 0x8 实现流量控制
    -CONTINUATION 0x9 传递较大HTTP头部时的持续帧
    设置帧 不是协商,而是通知,协商是有交互的,而通知是客户端或者浏览器直接告诉对方应该如何做 格式是: dientifier: value
    设置帧的类型
    SETTINGS_HEADER_TABLE_SIZE 0x1 通知对端索引表的最大的尺寸(单位字节,初始值4096字节)
    SETTINGS_ENABLE_PUSH  0x2 为0时可以禁用服务器推送功能,1时启用服务器推送功能
    SETTINGS_MAX_CONCURRENT_STREAMS 0x3 告诉接受端允许的最大并发数量(最大Stream数)
    SETTINGS_INITAL_WINDOW_SIZE 0x4 声明发送端的窗口大小,用于Stream级别流控(2的16次方-1字节)
    SETTINGS_MAX_FRAME_SIZE 0x5 设置 帧的最大值,初始值2^14字节
    SETTINGS_MAX_HEADER_LIST_SIZE 0x6 通知对端头部索引表的最大尺寸,单位字节,基于未压缩前的头部
060.HPACK
    HPACK是用于压缩HTTP头部的压缩算法,它主要是有两个索引表:静态映射表和动态映射表
    静态映射表就是固定的写死的例如1  动态映射表就是基于前面的请求,往HPACK映射里动态添加映射
    Huffman树
    HTTP头部的传输有三种方式
    -key和value都是使用HPACK算法进行压缩
    -key进行HPACK压缩,value不使用HPACK压缩
    -key和value都不使用HPACK压缩
    HEADER帧中使用相应的标志位来标识是否使用HPACK算法进行压缩
    如何控制头部是否进入动态映射表
    -进入动态表,提供给后续传输使用
    -不进入动态表
    -不进入动态表,并约定该头部永远都不仅如此动态表
    HEADER帧中使用相应的标志位来标识该HEADER是否进入动态映射表
    
060.服务器端推送消息
    服务器端的推送,必须基于一个请求,即服务器不能直接向客户端发起消息推送,而是先接收到一个客户端的请求
    例如服务器端请求一个HTML页面,这个HTML页面又依赖了一个CSS文件,那么基于请求的服务器推送是这样实现的
    客户端首先向服务器发送一个获取HTML页面的请求,
    服务器端在收到这个请求后,新起一个Stream流,开始发送应答帧,其中包含一个PUSH_PROMISE帧,这个帧告诉客户端接下来我要向你推送一个消息,这个帧里包含真正推送消息的那个流的StreamID
    服务发出这个响应后,新起一个Stream流,用于传送真正的推送帧(CSS文件)
061.Stream的状态变迁
    一条TCP连接上,可以并发存在多个处于OPEN状态的Stream
    客户端或者服务器端都可以创建新的Stream
    客户端或者服务器端都可以首先关闭Stream
    同一条Stream内的Frame是有序的
    从StreamID的值可以轻易分辨PUSH消息
    HTTP/2协议中消息的格式
    一条HTTP Message由1个HEADER(可能含有0个或多个持续帧构成)个0个或多个DATA帧构成
    HEADER消息同时包含HTTP/1.1的start line和headers部分
    取消HTTP/1.1中的不定长包体Chunk包体
    stream流的状态如下,
    A1.首先一个stream被创建之后处于idle状态
    A2.处于idle状态的stream在收到一个header帧之后,处于open状态
    A3.处于open状态的流如果收到一个RST_STRAM帧后就变成close状态
    B1.处于OPEN状态的Stream流如果接收到了一个带有END_STREAM标志位的帧,则处于half-closed(remote)状态,处于该状态的Stream不会再接受除了RST_STREAM帧以外的其他任何帧了
    B2.处于half-closed(remote)状态的Stream流在发送了一个含有END_STREAM标志位的数据帧或者发送一个RST_STREAM帧或者接收到一个RST_STREAM帧之后都会变成closed状态
    C1.处于OPEN状态的Stream流如果发出一个带有END_STREAM标志位的帧,则处于half-closed(local)状态,处于该状态的Stream不会再发送除了RST_STREAM帧以外的其他任何帧了
    C2.处于half-closed(local)状态的Stream流在接收到一个含有END_STREAM标志位的帧或者RST_STREAM帧 或者发送了一个RST_STREAM帧之后处于closed状态
062.RST_STREAM帧和其常见的错误码
    RST_STREAM用于立刻终止未完成的流
    RST_STREAM帧的常见错误码
    -NO_ERROR (0x0) 没有错误,GOAWAY帧优雅的关闭连接时可以使用此错误码
    -PROTOCAL_ERROR (0x1) 检测到不识别的协议字段,比如两边的版本不匹配时
    -INTERNAL_ERRPR (0x2) 内部错误,就是这个错误无法归类的时候
    -FLOW_CONTROL_ERROR (0x3) 检测到对方没有遵守流控策略
    -SETTINGS-TIMEOUT (0x4) 某些设置帧发出后需要接收端应答,在期待时间内没有得到应答则由此错误码表示
    -STREAM_CLOSED (0x5) 当Stream已经处于半关闭状态时不再接受Fream帧时又收到了对端的数据帧时,返回给对端的响应码
    -FREAM_SIZE_ERROR (0x6) 收到的帧的大小不合法
    -REFUSED_STREAM (0x7) 拒绝先前的Stream流的执行
    -CANCEL (0x8) 表示Stream不再存在
    -COMPESSION_ERROR (0x9) 对HPACK压缩算法执行失败
    -CONNECT_ERROR (0xa) 连接失败
    -ENHPACK_YOUR_CALM (0xb) 检测打对端的行为可能导致负载的持续增加,提醒对方“冷静”一点
    -INADEQUATE_SECURITY (0xc) 安全等级不够
    -HTTP_1_1_REQUIRED (0xd) 对端只能接受HTTP/1.1的请求
063.数据流优先级 Priority设置帧
    一个依赖的流ID (Stream Dependency),一个权重,依赖别的stream的stream必须要等待它依赖的stream传输完成了才能开始传送数据
    例如在网站的首页HTML(假设这个HTML包含一个CSS文件一个JS文件和张图片),它的StreamID是1 权重是255,那么后续的CSS 的 Stream Dependency 就是1 权重可能是219 而后面的JS Stream Dependency 就是1 权重可能是200 
       而最后的图片等资源 Stream Dependency 就是1 权重可能是149等等
    那么这CSS文件JS文件和图片文件的优先级分别是多少呢: 255/(255+200+149) 200/(255+200+149) 149/(255+200+149),在有流控的情况下,优先级越大的越先传输,所谓优先传输就是优先去阅读内存中对应的buffer然后将数据发送
    标志位:如果B和C都依赖A 这时新来了一个stream流D里面包含一个Priority帧,而且这个帧依赖流A,这个帧的标准位是0,那么BCD是同级的
            如果D的Priority帧的标志位是1(独占),那么则是B和C依赖D,D依赖A 这样子
064.HTTP/2流量控制
    在HTTP/1.1中是由TCP层进行流量控制的
    而TCP的流量控制包含两个概念,一个是滑动窗口,一个是拥塞控制
    滑动窗口就是一个TCP连接,它一次性可以接受的数据报文的大小
    拥塞控制是指,在同一台服务器上建立了许多许多的TCP连接,当连接数过多时就可能会导致连接之间互相影响,从而导致数据传输错误,这时候就会使用到TCP的拥塞控制来避免这种风险
        它的原理是:初始化一个最大的TCP连接数,等到服务器运行过程中,逐渐的增加这个最大连接数,直到趋于稳定时确定这个最大连接数,例如服务刚开始时设置的最大连接数可能只有100,在服务运行期间TCP进行监控
        发现10个最大连接数没问题,就试图增加这个最大连接数比如20,然后继续监控,一直到达一个最大值
    HTTP/2中是在应用层进行的流量控制
    原因1 是多个Stream争夺TCP的流控制,互相干扰可能会造成Stream的阻塞,
    原因2 是代理服务器内存有限,上下游网速不一致,通过流量来管理内存
    -HTTP/2中的流控既可以针对单个Stream,也可以针对整个TCP连接,HTTP/2的流量控制有两个方向,一个是控制一个连接或者一个Stream上传输的数据量大小,还有一个是控制一个TCP连接上并发的最大Stream数
    控制一个连接或者一个Stream上传输的数据量大小:
    -客户端与服务器都具备流量控制
    -单向流控制:发送和接受端独立设定流量大小
    -以信用为基础:接收端设定上限,发送端必须按照接收端设定的流量上限来发送数据报文
    -流量控制窗口:的初始值时65535字节
    -只有Data帧服从流量控制
    -流量控制不能被禁用
    WINDOW_UPDATE 控制帧 用于告知发送端,接收端能够接受多大的数据量
    .窗口范围(即最多能传输多少字节的数据):1 到 2^31 - 1 0是错误的,接收端应返回PROTOCAL_ERROR
    .当StreamID为0时表示这个流控作用于整个TCP连接,否则只针对于当前流
    .流控只针对一个TCP连接的两端
        代理服务器不透传WINDOW_UPDATE设置帧
        接收端缩小流控窗口最终会传递到源发送端
    .发送端在接收到WINDOW_UPDATE帧后是怎么执行的呢,假设收到的WINDOW_UPDATE帧的窗口范围是200字节,并且分成10个data帧来发送,那么假设先发送了2个data帧消耗掉了40字节,那么后面8个data真最多是能发送160字节的数据(并不一定是每一个data帧传输20字节)
    控制一个TCP连接上并发的最大Stream数:
    在StreamID为0的SETTINGS_MAX_CONNECURRENT_STREAMS设置帧来控制一个TCP连接上最大的并发Stream数
    该设置帧仅限制状态为open或者half-closed状态的流
    超出限制后的错误码: PROTOCAL_ERROR REFUSED_STREAM

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值