HTTP协议与TCP/IP协议的关系
HTTP的长连接和短连接本质上是TCP长连接和短连接。 HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议。 IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠地传递数据包,使得网络上接收端收到发送端所发出的所有包,并且顺序与发送顺序一致。TCP协议是可靠的、面向连接的。
在HTTP/1.0中,默认使用的是短连接。 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。
但从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。
1.TCP连接
TCP运输连接的三个阶段:
- 连接建立(三次握手)
- 数据传送
- 连接释放(四次挥手)
2.TCP短连接
客户端每次向服务器发起一次请求都要重新建立TCP连接。步骤:
建立连接——数据传输——关闭连接 ... 建立连接——数据传输——关闭连接
优点:
管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。
缺点:
如果客户请求频繁,将在TCP的建立和关闭操作上浪费较多的事件和带宽。
3.TCP长连接
客户端在第一次向服务器发起一次请求后,不断开连接,在一定时间内的请求都继续使用这个连接。步骤:
建立连接——数据传输 ...(保持连接)... 数据传输——关闭连接
优点:
长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。
缺点:
在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候。
所以针对这种现象,服务端需要采取一些策略,如关闭一些长时间没有请求发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件允许则可以限制每个客户端的最大长连接数,这样可以完全避免恶意的客户端拖垮整体后端服务。
TCP的保活功能
TCP的保活功能主要为服务器应用提供。如果客户端已经消失而连接未断开,则会使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,此时服务器将永远等待客户端的数据。保活功能就是试图在服务端器端检测到这种半开放的连接。
如果一个给定的连接在两小时内没有任何动作,服务器就向客户发送一个探测报文段,根据客户端主机响应探测4个客户端状态:
- 客户主机依然正常运行,且服务器可达。此时客户的TCP响应正常,服务器将保活定时器复位。
- 客户主机已经崩溃,并且关闭或者正在重新启动。上述情况下客户端都不能响应TCP。服务端将无法收到客户端对探测的响应。服务器总共发送10个这样的探测,每个间隔75秒。若服务器没有收到任何一个响应,它就认为客户端已经关闭并终止连接。
- 客户端崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。
- 客户机正常运行,但是服务器不可达。这种情况与第二种状态类似。
长连接的过期时间:
客户端的长连接不可能无限期的保持,会有一个上限,服务器有时候会告诉客户端超过时间,比如:
HTTP/1.1 200 OK
Server: ngx_openresty
Date: Tue, 08 Apr 2014 05:20:23 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Kepp-Alive: timeout=20
Vary: Accept-Enncoding
Last-Modified: Tue, 08 Apr 2014 05:20:01 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=20,表示这个TCP通道可以保持20秒。另外还可能有max=XXX,表示这个长连接最多接收XXX次请求就断开。对于客户端来说,如果服务器没有告诉客户端超时时间也没关系,服务端可能主动发起四次握手断开TCP连接,客户端能够知道该TCP连接已经无效;另外TCP还有心跳包来检测当前连接是否还活着,方法很多,避免浪费资源。