HTTP 持久连接 - awokezhou/LinuxPage GitHub Wiki
持久连接
通常来说,客户端访问Web页面的大部分内容来自于同一个站点,并且很大一部分的超链接资源页面也是指向同一个站点。这就意味着当客户向某个站点发起了初始请求之后,在未来的一段时间内很有可能有更多访问请求,这种性质被称为站点本地性(site locality)
HTTP/1.1以及其后的版本在TCP的连接管理上规定,允许在一次事务处理之后保持TCP连接,下一次事务可重用此连接,这种连接模式叫做持久连接
持久连接作为HTTP协议对TCP连接的一种性能优化方式,其优势是显而易见的。TCP的连接重用,避免了TCP慢启动、TCP连接建立所带来的时间和计算资源上的开销,但是如果连接管理不当,会出现大量空闲连接,消耗大量资源
目前持久连接有两种类型:HTTP/1.0 “Keep-alive” 和 HTTP/1.1 “persistend” 连接
HTTP/1.0 keep-alive
keep-alive现在已经不再使用,在HTTP/1.1规范中已经没有对keep-alive的说明了,但是浏览器与服务器对它的使用仍然非常广泛。对keep-alive详细的规范可查阅早期版本的HTTP/1.1 RFC 2068
如果浏览器希望在发送请求后保持与服务器的连接,通过在HTTP首部包含connection:keep-alive来告知服务器,服务器如果愿意保持该链接,则在HTTP应答报文中也包含该字段。如果服务器没有在应答报文中包含该字段,客户端认为浏览器不支持keep-alive,会关闭连接
client ------------------------> server
-- HTTP request -->
Connection:keep-alive
client <------------------------ server
<-- HTTP response --
Connection:keep-alive
Keep-Alive:timeout=60, max=60
connection don't close
Keep-Alive 选项
- timeout,在响应首部的Keep-Ailve字段中发送的,由服务器发送给客户端,表明服务器愿意为该连接保持的时间
- max,同样是在响应首部的Keep-Alive字段中发送,由服务器发送给客户端,表明服务器还愿意在该连接上支持多少次事务
注意
- Keep-Alive字段是可选的,必须包含Connection:keep-alive,Keep-Alive字段才有效
- Keep-Alive选项中的参数,都不是承诺值,服务器仍然可以在事务处理完成后断开连接
- 不能够与不确定是否支持Connection首部的代理服务器建立keep-alive连接,以防止出现哑代理
HTTP/1.1 persistend
HTTP/1.1默认激活,即TCP连接默认是持久的,要在事务处理后关闭连接,需要在首部中包含Connection:close
实现方案
keep alive的实现,共分为4个部分,初始化
keep_alive_init
、添加keep_alive_add
、检测keep_alive_check
和更新keep_alive_update
数据结构
根据keep-alive的选项,设计一个简易的结构,此结构用于记录一个TCP连接的keep-alive情况
def http_keep_alive{
fd; /* TCP连接的文件描述符 */
req_number; /* 此连接已经处理的事务数 */
time; /* 此连接建立的时间 */
ka_flag; /* keep-alive标志 */
list _head;
}
在服务器中,以链表keep_alive_list形式维护所有TCP连接的keep-alive结构
init
服务器初始化时,对keep_alive_list链表进行初始化
add
服务器接收到HTTP请求,解析后,如果发现首部有Connection:keep-alive内容,则进行添加操作,记录此时的时刻到time成员,初始化req_number为0,记录文件描述符到fd,设置ka_flag为alive
check
当一个事务处理完成后,服务器释放请求体,此时判断是否应该断开连接,判断条件有两条
- 获取当前时刻,计算当前时刻与time的差值,是否此差值 >= 服务器规定的keep-alive超时时间
- req_number++,并判断req_number值是否 >= 服务器规定的keep-alive最大处理事务数
如果以上任何一个条件不满足,则断开与客户端的连接
update
一个单独的任务,定时轮询每条连接的keep-alive超时时间是否到达,或者是否事务处理数到达上限,如果任意条件满足,则断开连接