HTTP连接

HTTP连接也经历了一个演变的过程,从最初的短连接,到现在的持久连接。

在知乎上,看到了一个比较不错的HTTP连接方式的进化史介绍(作者是王小二):

HTTP/0.9时代:

短连接每个HTTP请求都要经历一次DNS解析、三次握手、传输和四次挥手。反复创建和断开TCP连接的开销巨大,在现在看来,这种传输方式简直是糟糕透顶。

HTTP/1.0时代:

持久连接概念提出人们认识到短连接的弊端,提出了持久连接的概念,在HTTP/1.0中得到了初步的支持。持久连接,即一个TCP连接服务多次请求:客户端在请求header中携带Connection: Keep-Alive,即是在向服务端请求持久连接。如果服务端接受持久连接,则会在响应header中同样携带Connection: Keep-Alive,这样客户端便会继续使用同一个TCP连接发送接下来的若干请求。(Keep-Alive的默认参数是[timout=5, max=100],即一个TCP连接可以服务至多5秒内的100次请求)当服务端主动切断一个持久连接时(或服务端不支持持久连接),则会在header中携带Connection: Close,要求客户端停止使用这一连接。

HTTP/1.1时代:持久连接成为默认的连接方式;

提出pipelining概念HTTP/1.1开始,即使请求header中没有携带Connection: Keep-Alive,传输也会默认以持久连接的方式进行。目前所有的浏览器都默认请求持久连接,几乎所有的HTTP服务端也都默认开启对持久连接的支持,短连接正式成为过去式。(HTTP/1.1的发布时间是1997年,最后一次对协议的补充是在1999年,我们可以夸张地说:HTTP短连接这个概念已经过时了近20年了。)同时,持久连接的弊端被提出 —— HOLB(Head of Line Blocking)即持久连接下一个连接中的请求仍然是串行的,如果某个请求出现网络阻塞等问题,会导致同一条连接上的后续请求被阻塞。所以HTTP/1.1中提出了pipelining概念,即客户端可以在一个请求发送完成后不等待响应便直接发起第二个请求,服务端在返回响应时会按请求到达的顺序依次返回,这样就极大地降低了延迟。

我用wireshark做了一下测试:

用Ubuntu的Loopback做的测试,我在我自己主机利用Nginx部署了Django服务器。

初次访问目标地址,会先建立TCP连接,经历三次握手。TCP成功建立后,客户端发送GET请求。 我们看一下GET请求:

头部域有一个Connection:keep-alive.他表示请求将一条连接保持咋打开状态,如果服务器愿意为下一条请求将连接保持在打开状态,就在响应头部域中加上Connection:keep-alive,如下图:

在之后访问服务器其他地址时,不必像在第一次的时候再重新建立TCP了。

这里还要说一下,不管是客户端,还是服务器,发送一条HTTP消息后,对端都会发送一个TCP确认报文。说实话,这个不太懂,我只是猜测对端在接收到数据后,要发送一个Ack回来,告诉他我已经正确收到。

虽然,HTTP/1.1会持久化连接,但如果长时间没有数据传送,还要保持这个连接,势必会造成对资源的浪费。见下图:

如果超过了设置的HTTP的Keep-alive时间,那么服务器端会主动关闭TCP链接,看上图最下面黄色的部分。

除此之外,为了避免资源浪费,TCP也有一个检测机制,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。 当然,除非TCP的Keepalive时间小于HTTP的Keep-alive时间,否则TCP检测用不上。

注:HTTP的keep-alive和TCP的KeepAlive不同。

--------EOF---------
微信分享/微信扫码阅读