8 连接
8.1 持续连接(Persistent Connection)。
8.1.1目的
在持续连接之前,为获取 每一个URL指定的资源都必须建立了独立的TCP 连接, 这就加重了HTTP服务器的负担,易引起互联网的阻塞。嵌入的图片与其它相关数据通常使用户在短时间内对同一服务器提交多个请求。目前已有针对这些性能问 题的分析以及原型实现的结果[26][30]。 对其他方法也有了初步探究,如T/TCP [27]。

持续HTTP 连接有着诸多的优点:

--- 通过建立与关闭较少的TCP连接,不仅节省了路由器与主机(客户端,服务器,代理服务器,网关,隧道或缓存)的CPU时间,还节省了主机用于TCP协议控制块的内存。

---能在连接上进行流水线请求方式。 流水线请求方式能允许客户端执行多次请求而不用等待每一个请求的响应(译注:即客户端可以发送请求而不用等待以前的请求的响应到来后再发请求),并且此时只进行了一个TCP连接,从而效率更高,减少了时间。

--- 网络阻塞会被减少,这是由于TCP连接后减少了包的数量,并且由于允许TCP有充分的时间去决定网络阻塞的状态。

--- 因为无须在创建TCP连接时的握手上耗费时间,而使后续请求的等待时间减少。

---HTTP改进的越来越好,因为在不需要关闭TCP连接的代价下可以报告错误。将来的HTTP版本客户端可以乐观的尝试一个新的特性,但是如果和老的服务器通信时,在错误被报告后就要用旧的语义而进行重新尝试连接。

HTTP实现应该实现持久连接。

8.1.2总体操作
HTTP/1.1 与早期HTTP 版本的一个显著区别在于持续连接是任何HTTP/1.1连接的缺省方式。也就是说,除非另有指定,客户端总应当假定服务器会保持持续连接,即便在接到服务器的出错响应时也应如此。

持续连接提供了一种可以由客户端或服务器发信号来终止TCP连接的机制。利用Connect头域(14。10节)可以产生终止连接信号。一旦出现了终止连接的信号,客户端便不可再向此连接提出任何新请求。

8.1.2.1 协商(Negotiation)
除非请求的Connect头域中包含了"close"标签,HTTP/1.1服务器总可以 假定HTTP/1.1 客户端想要维持持续连接(persistent connection)。如果服务器想在发出响应后立即关闭连接,它应当发送一个含”close”的Connect头域。

一个HTTP/1.1客户端可能期望保持连接一直开着,但这必须是基于服务器响应里是否包含一个Connect头域并且此头域里是否包含”close”。如果客户端不想为更多的请求维持连接,它应该发送一个值为”close”的Connect头域。

如果客户端和服务器之一在发送的Connect头域里包含”close”,那么客户端的请求将会变为此连接的最后一个请求。。

客户端和服务器不应该认为持续连接是低于1.1的HTTP版本所拥有的,除非它被显示地指明了。19.6.2节指出了跟HTTP/1.1客户端兼容的更多信息。

 

8.1.2.2 流水线(pilelining)
支持持续连接(persistent conncetio)的客户端可以以流水线的方式发送请求(即无须等待响应而发送多个请求)。服务器必须按接收请求的顺序发送响应。

假定持续连接并且在连接建立后进行流水线方式请求的客户端应该准备去重新尝试他们的连接如果第一个流水线请求方式尝试失败。如果客户端重新尝试连 接,在客户端知道连接是持续之前客户端不能进行流水线发送请求。客户端必须准备去重新发送请求如果服务器在响应所有对应的请求之前关闭连接

客户端不应该利用非等幂的方法或者非等幂的方法序列(见9.1.2节)进行流水线方式的请求。否则一个过早的传输层连接的终止可能会导致不确定的结果。一个可能希望发送一个非等幂方法请求的客户端只有接收了上次它发出请求的响应后才能再次发送请求给服务器。

8.1.3代理服务器 (Proxy Servers)
它是非常重要的因为代理服务器正确地实现了Connect头域的属性,这在14.10节指出了。

代理服务器必须分别向和它相连的客户端或者源服务器(或其他的代理服务器)指明持续连接。每一个持续连接只能应用于一个传输层连接。

代理服务器不能和一个HTTP/1.0客户端建立一个HTTP/1.1持续连接(但是参见RFC2068[33]里的关于许多HTTP/1.1客户端利用Keep-Alive头域的问题的讨论)。

8.1.4实际的考虑 (Practical Considerations)
服务器通常有一个时限值,超过一定时间即不再维持处于非活动的连接。代理服务器会选一个较高的值,因为客户端很可能会与同一服务器建立多个连接。持续连接方式的采用对于客户端与服务器的时限均未提出任何要求。

当客户端或服务器希望超时终止时, 它应该按规范终止传输连接。客户端与服务器端应始终注意对方是否终止了连接,并适当的予以响应。若客户端或服务器未能及时检测到对方已终止了连接,将会造成不必要的网络资源浪费。

客户端,服务器,或代理服务器可能在任意时刻会终止传输连接。比如,客户端可能正想发出新的请求,而此时服务器却决定关闭"闲置"的连接。在服务器看来,连接已经因为闲置被关闭了, 但客户端认为我正在请求。

这表明客户端,服务器与代理服务器必须有能力从异步的连接终止事件中恢复。只要请求是等幂的(见9.1.2节),客户端软件应该能重新打开传输层连 接并重新传输遗弃的请求序列而不需要用户进行交互来实现。对非等幂方法的请求不能自动进行重试请求,尽管客户代理(user agent)可能能提供一个人工操作去重试这些请求。应该用用户代理(user-agent)软件对应用程序语义识别的确认来替代用户的确认。如果再次重 试请求失败,那么就不能再进行重复请求了。

服务器尽可能应该在每次连接中至少响应一个请求。除非出于网络或客户端的故障,服务器不应在传送响应的中途断开连接。

使用持续连接的客户端应限制与某一服务器同时连接的个数。单用户客户端不应与任一服务器或代理服务器保持两个以上的连接。代理服务器与其它服务器或代理服务器之间应维护2*N个连接,其中N是同时在线的用户数。这些准则是为了改善响应时间和和避免阻塞。

8.2 消息传送要求(Message Transmission Requirements)
8.2.1持续连接与流量控制 (Persistent Connections and Flow Control)
HTTP/1.1服务器应当保持持续连接并使用TCP流量控制机制来解决临时过载,而不是在终止连接后指望客户端的重试。后一方法会恶化网络阻塞。

8.2.2监视连接中出错状态的消息
HTTP/1.1(或更新)客户端应在发送消息主体的时候同时监视网络连接是否处于出错状态。若客户端 发现了错误,它应当立即停止消息主体的的传送。若正文是以块传输编码方式发送的(3.6节),可以用长度为零的块和空尾部来提前标记报文结束。若消息主体 前有Content-Length头域,则客户端必须关闭连接。

8.2.3 100状态码的用途
100状态码(继续,见10.1.1节)的目的在于允许客户端判定服务器是否愿意接受客户端发来的消息主体(基于请求头域)在客户端发送此请求消息主体前。 在有些情况下,如果服务器拒绝查看消息主体,这时客户端发送消息主体是不合适的或会降低效率。

HTTP/1.1客户端的要求:

--- 若客户端要在发送请求消息主体之前等候100(继续)响应,则它必须发送一个Expect请求头域(见14.20节),并且值是”100-continue”。

--- 客户端不能发送一个值是”100-continue”的Expect请求头域,如果此客户端不打算发送带消息主体的请求。

由于存在旧的实现方法,协议允许二义性的情形存在,这在客户端在发送”Expect:100-continue”后而没有接收一个417(期望失 败)状态码或着100(继续)状态码的情况下发生。因此,当一个客户端发送此头域给一个源服务器(可能通过代理),此服务器也没有以100(继续)状态码 响应,那么客户端不应该在发送请求消息的主体前无限等待。

HTTP’/1.1源服务器的要求:

--- 当接收一个包含值为”100-contitue”的Expect请求头域的请求时,源服务器必须或者以100(继续)状态码响应并且继续从输入流里接收数 据,或者以final状态码响应。源服务器不能在发送100(继续)状态码响应之前接收请求主体。如果服务器以final状态码响应后,它可能会关闭传输 层连接或者它也可能会继续接收或遗弃剩余的请求。但是既然它返回了一个final状态码的响应,它就不能再去那个执行请求的方法(如:POST方 法,PUT方法)。

--- 如请求消息不含值为"100-continue"的Expect请求头域, 源服务器不应发送100(继续)响应。当请求来自HTTP/1.0(或更早)的客户端时也不得发送100(继续)响应。对此规定有一例外:为了与RFC 2068兼容,源服务器可能会发送一个100(继续)状态响应以响应HTTP/1.1的PUT或POSt请求,虽然这些请求中没有包含值为”100- continue”的Expect请求头域。这个例外的目的是为了减少任何客户端因为等待100(继续)状态响应的延时,但此例外只能应用于 HTTP/1.1请求,并不适合于其他HTTP版本的请求。

--- 若已经接收到部分或全部请求的消息的主体,源服务器可以不需要发100(继续)响应。

--- 发送100(继续)响应的源服务器必须最终能发送一个final状态响应,一旦请求消息主体被它接收到并且已经被它处理了,除非源服务器过早切断了传输层连接。

--- 若源服务器接收到不含值为"100-contitue"的Expect请求头域的请求,该请求含有请求消息主体,而服务器在从传输层连接上接收整个请求消 息主体前返回一个final的状态响应,那么此源服务器不能关闭传输层连接直到它接收了整个请求或者直到客户端关闭了此连接。否则客户端可能不会信任接收 此响应消息。然而,这一要求不应该被解释用来防止服务器抵抗服务***,或者防止服务器被客户端实现***。

对HTTP/1.1代理服务器的要求:

--- 若代理服务器接到一个请求,此请求包含值为"100-continue"的Expect请求头域,并且代理服务器可能知道下一站点的服务器遵循 HTTP/1.1或更高版协议,或者不知道下一站点服务器的HTTP版本,那么它必须包含此Expect头域来转发此请求。

--- 若代理服务器知道下一站点服务器版本是HTTP/1.0或更低,则它不能转发此请求,并且它必须以417(期望失败)状态响应。

--- 代理服务器应当维护一个缓存,以记录最近访问下一站点服务器的HTTP版本号。

--- 若接收到的请求来自于版本是HTTP/1.0(或更低)的客户端,并且此请求不含值为"100-continue"的Expect请求头域,那么代理服务器不能转发100(继续)响应。 这一要求可覆盖1xx响应转发的一般规则(参见10.1节)。

8.2.4服务器过早关闭连接时客户端的行为
如果HTTP/1.1 客户端发送一条含有消息主体的请求消息,但不含值为"100-continue"的Expect请求头域,并且客户端直接与HTTP/1.1源服务器相 连,并且客户端在接收到服务器的状态响应之前看到了连接的关闭,那么客户端应该重试此请求。在重试时,客户端可以利用下面的算法来获得可靠的响应。

1. 向服务器发起一新连接。

2. 发送请请求头域。

3. 初始化变量R,使R的值为通往服务器的往返时间的估计值(比如基于建立连接的时间),或在无法估计往返时间时设为一常数值5秒。

4. 计算T=R*(2**N),N为此前重试请求的次数。

5. 等待服务器出错响应,或是等待T秒(两者中时间较短的)。

6. 若没等到出错响应,T秒后发送请求的消息主体。

7. 若客户端发现连接被提前关闭,转到第1步,直到请求被接受,接收到出错响应,或是用户因不耐烦而终止了重试过程。

在任意点上,客户端如果接收到服务器的出错响应,客户端

--- 不应再继续发送请求, 并且

--- 应该关闭连接如果客户端没有完成发送请求消息。