http2协议之底层原理抓包分析与视频讲解
Posted 程序员大新
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了http2协议之底层原理抓包分析与视频讲解相关的知识,希望对你有一定的参考价值。
本文将尽量以通俗易懂的方式讲解到底啥是http2.0协议,它与http1.0/1.1到底有什么区别,它的优势是什么?
一、TCP连接数量与方式上的区别
HTTP1.0时代
每一次请求创建一个新的tcp连接,用完即关闭连接,请看下图:
上图中,请求一个静态html页面,内部加载了10张图片和5个css文件,可以看到响应头为Connection:close,每个请求对应一个tcp连接,假设我有100个请求,那么它就会创建100个tcp连接,非常消耗资源。
我们在看一下服务器的tcp连接数 netstat -ntp | grep -w 443:
上图中,我们看到服务器中有大量已经关闭的tcp连接。
HTTP1.1时代
访问一个域名,假设有100个请求,只会创建5-6个TCP连接(我用谷歌浏览器测试的,其它浏览器会有些不同,不在这里讨论),连接会复用。
请看下图:
上图中,请求头和响应头都是keep-alive,那么服务器和浏览器会保持5-6个TCP长连接,假设我有100个请求,他们会复用这5-6个TCP连接。
我们在看一下服务器的tcp连接数 netstat -ntp | grep -w 443:
可以看到服务器只有5个TCP连接,这些请求会复用TCP连接。
复用原理如下图:
这里值得注意的是,http1.1的tcp连接复用是串行的,我叫他串行复用,请求tomcat1.css 响应tomcat1.css, 请求tomcat2.css响应tomcat2.css,以此类推。
HTTP2.0时代
访问一个域名,假设有100个请求,只会创建1个TCP连接,连接会复用,而且是多路复用(重点)后面会单独讲
请看下图:
上图中,我们发现请求头明显与http1.1不同,已经使用了http2.0新协议。
我们在看一下服务器的tcp连接数 netstat -ntp | grep -w 443:
可以看到,服务器端只有1个tcp连接。
http1.0,http1.1,http2.0在tcp连接数上的区别
http1.0:每个请求创建一次tcp连接,不复用,非常浪费资源,效率低。
http1.1:所有请求创建5-6个tcp连接,串行复用,节省资源,效率高。
http2.0:所有请求创建1个tcp连接,多路复用,非常节省资源,效率非常好。
多说两句
以一个https的网站为例,现在几乎所有网站都是https的,这也是未来趋势。 一个tcp的创建需要三次握手(1.5次RTT),ssl四次握手(2次RTT)。加上tcp的慢启动机制,所有tcp创建的开销是比较大的。
二、兼容HTTP1.1/1.0
先决条件
要使用Http2.0协议,网站必须配置为https的,因为浏览器与服务器协商是否支持H2协议是通过SSL握手阶段完成的,其实现在绝大多数网站几乎都是https的。
协商原理
客户端发送请求到服务器端,首选是TCP三次握手,三次握手之后,就是SSL的四次握手,那么客户端与服务器协商双方是否支持H2协议,就在SSL握手的过程中,我们抓包看分析。
客户端SSL的第一次握手,如下图:
上图中是客户端SSL握手的第一个数据包,发送了ALPN NextProtocol:H2,说明浏览器支持H2。
我们在看服务器端的Server Hello包。如下图:
上图中,nginx配置了支持HTTP2.0协议,所以服务器端选择了H2协议,那么浏览器就会用2.0协议与服务器交互,否则就用1.1。
三、头部压缩技术
压缩意义
在HTTP请求中,主要由(请求 / 响应头部、消息主体)组成,消息主体可以使用GZIP等压缩技术,或者本身就是压缩过的数据,如图片,视频等。但是(请求/响应头)是没有经过任何压缩的。
我们访问一个网站,平均一个页面有几十到上百个资源,每次都要传输cookie,agent等不经常变化的头,完全是一种浪费。
HTTP2的头部压缩抓包
我们使用Wireshark抓取访问H2网站的数据包,第一个请求的抓包图。
从图片可与看到,请求头压缩前485个字节,而压缩后只有255个字节。
我们接着抓取后续的几个请求头的数据包:
可以看到,压缩前433个字节,压缩后只有63个字节,压缩了差不多8倍。
为什么两次请求头部压缩大小差了这么多,我们把俩个请求的包放在一起对比一下:
对比后可以发现,第二次的请求头部之所以非常小,是因为大部分的键值对都用了一个字节,后续的请求都只需要1个字节。
HTTP2头部压缩原理
1:静态压缩
浏览器和服务器维护一张内容相同的静态表。
假如请求头为 :method GET,则实际传输的值为2, 到服务器在把2转换为 :method GET,我们看一下静态压缩的原理
整个头部键值对都在字典中
这是最简单的情况,使用一个字节就可以表示这个头部了,最左一位固定为 1,之后七位存放键值对在静态或动态字典中的索引。例如下图中,头部索引值为 2(0000010),在静态字典中查询可得 :method: GET
。
2:动态压缩(头部名称在字典中,更新动态字典)
对于这种情况,首先需要使用一个字节表示头部名称:左两位固定为 01,之后六位存放头部名称在静态或动态字典中的索引【01000001】,那么直为1,字典中头的值为:authority。
接下来的一个字节第一位 H 表示头部值是否使用了哈夫曼编码,剩余七位表示头部值的长度 L,后续 L 个字节就是头部值的具体内容了【10001010】,第一位为1表示启动了哈夫曼编码,剩余7为值为10,表示后续10个字节的内容是:authority的值,将其用哈夫曼解码后得到192.168.80.110。
3:其它情况
还有其它头部压缩的各种情况,这里不做详细讨论,本文注重讲解H2的优势与原理,至于协议本身的规范细节,后期再出详细的教程讲解。
四、多路复用
http1.1的串行复用
在HTTP1.1当中,底层TCP连接也是可以进行复用的,但1.1的复用是串行的,看图:
可以看到,三个请求都用了一个相同的TCP(62137)连接, 但是请求和响应是依次进行的, 请求1-响应1,请求2-响应2,请求3-响应3。
http2.0的多路复用
在h2当中,所有请求使用单一的TCP长连接,而且请求和响应可以并发进行,看图:
上图中,你能看到,一个TCP数据包中,包含了6个请求,浏览器同时并发的发送了6个请求在一个包内。我们在看服务器的响应,看图:
可以看到,服务器可以在同一个TCP数据包内返回多个响应,这里有一个问题,就是浏览器并发的同时发送了6个请求(1-6),那么服务器的响应是响应1呢,还是2呢,或者是6呢,请求和响应是怎么对应上的呢
看图:
浏览器在发送请求时,会把请求封装成一个一个的数据帧,每个请求有一个ID,即STREAM ID。那么服务器会根据ID进行响应,看图:
可以看到,每个响应的数据帧都包含了ID,和请求一一对应,这样浏览器就知道哪个请求对应哪个响应了。
以上是关于http2协议之底层原理抓包分析与视频讲解的主要内容,如果未能解决你的问题,请参考以下文章