文章是学习记录使用,摘自《HTTP权威指南》
连接管理
HTTP是如何使用TCP连接的;
TCP连接的时延、瓶颈以及存在的障碍;
HTTP的优化,包括并行连接、keep-alive(持久连接)和管道化连接,
管理连接时应该以及不应该做的事情。
在任意时刻计算机都可以有几条TCP连接处于打开状态。TCP是通过端口号来保持所有这些连接的正确运行的。
TCP 连接是通过4个值来识别的:
<源P地址、源端口号、目的IP地址、目的端口号>
这4个值一起唯一地定义了一条连接。两条不同的TCP连接不能拥有4个完全相同的地址组件值(但不同连接的部分组件可以拥有相同的值)。
还有几种现存和新兴的方法可以提高HTTP的连接性能。
并行连接
通过多条TCP连接发起并发的HTTP请求。
·持久连接
重用TCP连接,以消除连接及关闭时延。
·管道化连接
通过共享的 TCP连接发起并发的 HTTP请求。
·复用的连接
交替传送请求和响应报文
并行连接可以提高复合页面的传输速度。但并行连接也有一些缺点。
·每个事务都会打开/关闭一条新的连接,会耗费时间和带宽。
·由于TCP慢启动特性的存在,每条新连接的性能都会有所降低。
·可打开的并行连接数量实际上是有限的。
持久连接有一些比并行连接更好的地方。持久连接降低了时延和连接建立的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量。但是,管理持久连接时要特别小心,不然就会累积出大量的空闲连接,耗费本地以及远程客户端和服务器上的资源。
持久连接与并行连接配合使用可能是最高效的方式。现在,很多Web应用程序都会打开少量的并行连接,其中的每一个都是持久连接。持久连接有两种类型:比较老的 HTTP/1.0+“keep-alive”连接,以及现代的 HTTP/1.1“persistent”连接。
使用keep-alive连接时有一些限制和一些需要澄清的地方。
·在HTTP/1.0中,keep-alive并不是默认使用的。客户端必须发送一个Connection: keep-Alive请求首部来激活keep-alive连接。
Connection: Keep-Alive首部必须随所有希望保持持久连接的报文一起发送。·如果客户端没有发送 connection: Keep-Alive首部,服务器就会在那条请求之后关闭连接。
·客户端探明响应中没有connection: Keep-Alive响应首部,就可以知道服务
器发出响应之后是否会关闭连接了。
HTTP/1.1逐渐停止了对keep-alive连接的支持,用一种名为持久连接(persistentconnection)的改进型设计取代了它。持久连接的目的与keep-alive连接的目的相同,但工作机制更优一些。
与HTTP/1.0+的keep-alive连接不同,HTTP/1.1持久连接在默认情况下是激活的。除非特别指明,否则 HTTP/1.1假定所有连接都是持久的。要在事务处理结束之后将连接关闭,HTTP/1.1应用程序必须向报文中显式地添加一个connection:close首部。这是与以前的 HTTP协议版本很重要的区别,在以前的版本中,keep-alive连接要么是可选的,要么根本就不支持。
HTTP/1.1客户端假定在收到响应后,除非响应中包含了Connection: close首部,不然HTTP/1.1连接就仍维持在打开状态。但是,客户端和服务器仍然可以随时关闭空闲的连接。不发送 connection: close并不意味着服务器承诺永远将连接保持在打开状态。
连接关闭容限、重试以及幂等性
即使在非错误情况下,连接也可以在任意时刻关闭。HTTP应用程序要做好正确处理非预期关闭的准备。如果在客户端执行事务的过程中,传输连接关闭了,那么,除非事务处理会带来一些副作用,否则客户端就应该重新打开连接,并重试一次。对管道化连接来说,这种情况更加严重一些。客户端可以将大量请求放入队列中排队,但源端服务器可以关闭连接,这样就会留下大量未处理的请求,需要重新调度。副作用是很重要的问题。如果在发送出一些请求数据之后,收到返回结果之前,连接关闭了,客户端就无法百分之百地确定服务器端实际激活了多少事务。有些事务,比如 GET一个静态的HTML页面,可以反复执行多次,也不会有什么变化。而其他一些事务,比如向一个在线书店POST一张订单,就不能重复执行,不然会有下多张订单的危险。
如果一个事务,不管是执行一次还是很多次,得到的结果都相同,这个事务就是幂等的。实现者们可以认为GET、HEAD、PUT、DELETE、TRACE和OPTIONS方法都共享这一特性。"客户端不应该以管道化方式传送非幂等请求(比如 POST)。否则,传输连接的过早终止就会造成一些不确定的后果。要发送一条非幂等请求,就需要等待来自前一条请求的响应状态。
TCP 连接是双向的。TCP连接的每一-端都有一个输入队列和一个输出队列,用于数据的读或写。放入一端输出队列中的数据最终会出现在另一端的输入队列中。
1.完全关闭与半关闭
应用程序可以关闭TCP输入和输出信道中的任意一个,或者将两者都关闭了。套接字调用close(〉会将TCP连接的输入和输出信道都关闭了。这被称作“完全关闭”,还可以用套接字调用shutdown()单独关闭输入或输出信道。这被称为“半关闭”
完全关闭和半关闭
关闭连接的输出信道总是很安全的。连接另端的对等实体会在从其缓冲区中读出所有数据之后收到一条通知,说明流结束了,这样它就知道你将连接关闭了
。
关闭连接的输入信道比较危险,除非你知道另一端不打算再发送其他数据了。如果另一端向你已关闭的输入信道发送数据,操作系统就会向另一端的机器回送一条TCP“连接被对端重置”的报文,大部分操作系统都会将这种情况作为很严重的错误来处理,删除对端还未读取的所有缓存数据。对管道化连接来说这是非常糟糕的事情。