Http请求的TCP连接

我们一直认为,HTTP连接分为长连接和短连接,而我们现在常用的都是HTTP1.1,因此我们用的都是长连接。

  这句话其实只对了一半,我们现如今的HTTP协议,大部分都是1.1的,因此我们平时用的基本上都是长连接。但是前半句是不对的,HTTP协议根本没有长短连接这一说,也正因为误解了这个,导致LZ对于长连接一直不明不白,始终不得其要领,具体下面一段会说到。

  网络上很多文章都是误人子弟,根本没有说明白这个概念。这里LZ要强调一下,HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了,或者更准确的说,是本次HTTP请求就结束了,根本没有长连接这一说。那么自然也就没有短连接这一说了。

  之所以网络上说HTTP分为长连接和短连接,其实本质上是说的TCP连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这一说

  其实知道了以后,会觉得这很好理解。HTTP协议说到底是应用层的协议,而TCP才是真正的传输层协议,只有负责传输的这一层才需要建立连接。

  一个形象的例子就是,拿你在网上购物来说,HTTP协议是指的那个快递单,你寄件的时候填的单子就像是发了一个HTTP请求,等货物运到地方了,快递员会根据你发的请求把货物送给相应的收货人。而TCP协议就是中间运货的那个大货车,也可能是火车或者飞机,但不管是什么,它是负责运输的,因此必须要有路,不管是地上还是天上。那么这个路就是所谓的TCP连接,也就是一个双向的数据通道。

  因此,LZ现在甚至觉得,“HTTP连接”这个词就不应该出现,它只是一个应用层的协议,根本就没有所谓的连接这一说,就像FTP也是应用层的协议,但是你有听说过FTP连接吗?(恩,好像是听过,-_-,但你现在知道了,其实所谓的FTP连接,严格来说,依旧是TCP连接)

  实际上,说HTTP请求和HTTP响应会更准确一些,而HTTP请求和HTTP响应,都是通过TCP连接这个通道来回传输的。

  不管怎么说,一定要务必记住,长连接是指的TCP连接,而不是HTTP连接。

  长连接是为了复用,这个在之前LZ就明白。那既然长连接是指的TCP连接,也就是说复用的是TCP连接。那这就很好解释了,也就是说,长连接情况下,多个HTTP请求可以复用同一个TCP连接,这就节省了很多TCP连接建立和断开的消耗。

  比如你请求了博客园的一个网页,这个网页里肯定还包含了CSS、JS等等一系列资源,如果你是短连接(也就是每次都要重新建立TCP连接)的话,那你每打开一个网页,基本要建立几个甚至几十个TCP连接,这浪费了多少资源就不用LZ去说了吧。

  但如果是长连接的话,那么这么多次HTTP请求(这些请求包括请求网页内容,CSS文件,JS文件,图片等等),其实使用的都是一个TCP连接,很显然是可以节省很多消耗的。

  另外,最后关于长连接还要多提一句,那就是,长连接并不是永久连接的。如果一段时间内(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间),这个连接没有HTTP请求发出的话,那么这个长连接就会被断掉。

下面是一些实验数据:

  一次HTTP请求的连接及请求响应过程,实际上,我门观察一次网页请求抓取的所有包,发现其中一共建立了4个TCP连接,在下图中显示了其中的2个连接的握手信息。

这4个连接分别用在了获取页面中引入的样式表、样式表中的字体图片等信息。截取部分依赖:

  实际上,一个页面所引用的所有组件,包括样式表、图片、脚本等都是一次HTTP请求,从Network中可以看出本次页面请求一共进行了包含HTML文档在内的7次HTTP请求:

这些请求分在4个TCP连接中进行。具体在抓包中有所体现,举一个例子来说吧:

  这里对页面中引用的normalize.css就是通过另一个TCP连接获取的,通过端口号可以区分,这里是建立在60546端口的TCP连接,不同于上面的60545。

实际上浏览器在这里使用了并行连接用来客服单条TCP连接的空载时间以及带宽限制。就像下面一样:

  浏览器会使用并行连接来提升效率,但是需要知道的是,TCP连接本身就会消耗较多的资源。对于一个页面中包含几十上百个HTTP请求的情况,开启几十个TCP连接是不可能的。通常,浏览器会将连接数限制4。本例中,我统计了抓包信息,恰好开启了4个TCP连接。

连接的关闭

  HTTP基于TCP,TCP又是面向连接的协议。连接有建立就有关闭,我在抓包的时候发现,当所有请求数据都发送完毕的时候,TCP连接并没有马上关闭。

我们回过头看第一个HTTP请求头信息:

其中有一项:Connection: keep-alive

返回头:

返回头中也有Connection: keep-alive

  在HTTP请求中,keep-alive用来告诉服务器我希望建立一个持久连接,也就是在数据发送完毕后不立即关闭该TCP连接。持久连接能够避免重复地打开关闭连接的消耗同时也能回避TCP慢启动特性带来的损耗。如果服务器同意建立该持久连接,就在响应头中同样包含Connection: keep-alive,否则客户端就会认为服务器不支持keep-alive。本连接是一个持久连接。

  通常持久连接的响应首部还会包含timeout以及max参数,用来估计服务器将连接保持活跃的时长以及保持持久连接数的上限。注意,该值只是估计,不是承诺。不过这里的响应头中并没有包含此类信息。

  本网站我是使用Express框架做的后台,我没有手动设置timeout以及max,也没查到其默认timeout时长,不过我用系统时钟进行了测试,在数据发送完毕后120s左右,TCP连接中断:

上图中包含了所有4个TCP连接断开的4次挥手信息。

  我发现,在手动关闭网页时也不会立即断开TCP连接。在连接期间刷新网页会继续使用已经建立的TCP连接。但是,如果关闭浏览器,会立即断开TCP连接。

猜你喜欢

转载自www.cnblogs.com/guanghe/p/9216932.html