每次传输数据,都需要建立新的链接,这种连接我们称为短连接。
由上面分析可知,短连接极大的降低了传输效率,每次有什么数据需要传输,都要重新进行三次握手和四次挥手。
早期的HTTP是短连接的,或称为无连接。
4.3.2、为什么要有长连接为了解决效率问题,于是出现了长连接。由上面分析可知,短连接传输效率低,所以,自从HTTP/1.1开始,默认就支持了长连接,也称为持久连接。
所谓长连接,就是在跟服务端约定,本次创建的连接,后边还会继续用到。于是,这样约定之后,TCP层通过TCP的keep-alive机制维持TCP连接。
TCP如何维持连接呢,这里介绍系统内核的三个相关配置参数:
net.ipv4.tcp_keepalive_intvl = 15;
net. ipv4.tcp_keepalive_probes = 5;
net.ipv4.tcp_keepalive_time = 1800;
当TCP连接闲置了tcp_keepalive_time秒之后,服务端就尝试向客户端发送侦测包,来判断TCP连接状态,如果侦测后没有收到ack反馈,那么在tcp_keepalive_intvl秒后再次尝试发送侦测包,知道接收到ack反馈。一共会尝试tcp_keepalive_probes次侦测请求。如果尝试tcp_keepalive_probes次之后,依然没有收到ack包,那么就会丢弃这个TCP连接了。
使用长连接的HTTP协议,会在响应头加入这个:
Connection: keep-alive如下图:
客户端和服务器一旦建立连接之后,可以一直复用这个连接进行传输。
4.3.3、长连接问题 4.3.3.1、如何避免长连接资源浪费如果建立长连接之后,一直不用,对于服务器来说是多么浪费资源呀。为此需要有关闭长连接的机制。
场景的控制手段:
系统内核参数设置:如上一节提到的几个参数;
客户端请求头声明:
请求头声明Connection: close,本次通信技术之后就关闭连接。
服务端配置:如Nginx,设置
keepalive_timeout:设置长连接超时时间;
keepalive_requests:设置长连接请求次数上限。
4.3.3.2、长连接的缺点我们可以建立起TCP长连接,但是HTTP/1.1是请求应答模型的,只要一个请求还没有收到应答,当前TCP连接就不可以发起下一个请求,也就是HTTP请求队头阻塞:
当前客户端与服务端值创建了一个已连接套接字,即一个TCP连接,客户端所有请求都通过这个TCP连接发送,由于request 1请求还没有接收到应答,其他的request就不能发起请求了。
为了减小请求阻塞等待的影响,于是人们考虑在同一个浏览器里面开启多个TCP连接,这样,即使一个TCP被阻塞了,还有另外的可以继续发起请求。
不过客户端开太多TCP连接,会导致服务器承受更大的压力。在RFC2616中限制客户端最多并发两个,但是目前大部分浏览器支持6个或者更多的并发连接数。
为了进一步优化前端加载请求,这个时期出现了很多各式的前端优化小技巧,如:
为了增加并发请求,做域名拆分,这样就突破了浏览器对并发请求数的限制了;
CSS、JS等资源内联到HTML中,或者进行资源合并,从而减少客户端的并发请求数;
生成精灵图,一次性传输所有小图标,从而减少客户端的并发请求数;
资源预取...
不过,HTTP/2解决了HTTP请求的队头阻塞,有些原有的优化在HTTP/2中则成为了反模式,如:域名拆分后需要建立多个域名的连接,精灵图或者合并CSS、JS等导致不能更灵活的控制缓存...
4.3.4、管道化长连接管道传输技术是在HTTP/1.1中引入的,在HTTP/1.0中不存在。
HTTP管道传输技术可以在单个TCP连接上连续发送多个HTTP请求,而无需等待响应,截止2018年,由于一些问题(如错误的代理服务器和TCP队头阻塞),现代浏览器默认未启用管道。
引入了管道技术之后的长连接如下图: