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字段中发送,由服务器发送给客户端,表明服务器还愿意在该连接上支持多少次事务

注意

  1. Keep-Alive字段是可选的,必须包含Connection:keep-alive,Keep-Alive字段才有效
  2. Keep-Alive选项中的参数,都不是承诺值,服务器仍然可以在事务处理完成后断开连接
  3. 不能够与不确定是否支持Connection首部的代理服务器建立keep-alive连接,以防止出现哑代理

HTTP/1.1 persistend

HTTP/1.1默认激活,即TCP连接默认是持久的,要在事务处理后关闭连接,需要在首部中包含Connection:close

实现方案

keep alive实现 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

当一个事务处理完成后,服务器释放请求体,此时判断是否应该断开连接,判断条件有两条

  1. 获取当前时刻,计算当前时刻与time的差值,是否此差值 >= 服务器规定的keep-alive超时时间
  2. req_number++,并判断req_number值是否 >= 服务器规定的keep-alive最大处理事务数

如果以上任何一个条件不满足,则断开与客户端的连接

update

一个单独的任务,定时轮询每条连接的keep-alive超时时间是否到达,或者是否事务处理数到达上限,如果任意条件满足,则断开连接