天天看点

第4章 连接管理

1、TCP连接

TCP是可靠的数据传输通道。TCP流是分段的,由IP分组传送。

2、对TCP性能的考虑

2.1、HTTP事务的时延:首先客户端会根据URL进行DNS查询,如果没有DNS cache,则要花费一些时间进行查询。然后客户端会向服务器发送一条TCP连接请求,服务器收到请求后会回送一条响应,这需要一定的时间。TCP连接建立后客户端向服务器发送HTTP请求报文,服务器对其进行处理,并回送HTTP响应,这些都需要时间。

2.2、TCP连接的握手时延:TCP建立有一个三此握手。客户端发送一个标记为SYN的数据包,服务器收到后,回送SYN+ACK的数据包,客户端收到后发送ACK数据包,并且现在允许客户端在这个确认数据包中一并发送数据。

2.3、延迟确认:TCP通过确认机制来确保数据的成功传输。每个TCP段都有一个序列号和数据完整性校验和。每个段的接收者收到完好的段时,都会向发送者回送小的确认分组。如果发送者没有在指定的窗口时间内收到确认信息,则认为分组已被破坏或损毁,并重发数据。由于确认报文很小,所以TCP允许在发往相同方向的输出数据分组中对其进行“捎带“,这样可以更有效地利用网络。而延迟确认算法会在一个特定的窗口时间内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组。若在那个时间段内没有输出数据分组,则单独传送。但是HTTP具有双峰特征的请求-应答行为降低了捎带信息的可能,当希望有相反方向回传分组的时候,偏偏没有那么多。通常,延迟确认算法会引入相当打的时延。当然可以对延迟确认算法进行调整或禁止。

2.4、TCP慢启动:TCP连接会随着时间进行自我“调谐”,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。简单来说,就是每成功发送一个分组,发送端就有了发送另外两个分组的权限,每个分组都被确认后,就可以发送四个分组,这被称为“打开拥塞窗口”。

2.5、Nagle算法与TCP_NODELAY:Nagle算法试图在发送一个分组之前,将大量TCP数据绑定在一起,以提高网络效率。但是Nagle算法会引发几种问题。首先,小的HTTP报文可能无法填满一个分组,因为等待哪些永远不会到来的额外数据而产生时延。其次,Nagle算法与延迟确认之间的交互存在问题,Nagle算法会阻止数据的发送,直到有确认分组抵达为止。HTTP应用程序可以通过设置TCP_NODELAY参数来禁用Nagle算法。

2.6、TIME_WAIT累积与端口耗尽:当某个TCP端口关闭TCP连接时,会在内存中维护一个小的控制块,用来记录最近所关闭连接的IP地址和端口号。通常维持2分钟的时间。这个算法可以防止在2分钟内创建、关闭并重新创建两个具有相同IP地址和端口号的连接。

3、HTTP连接的处理

如果对事务进行串行加载,即发送一个请求收到一个响应,再发送一个请求接收一个响应。比如加载一副图片时页面上其他地方都没有动静会让人觉得速度很慢。用户更希望能够同时加载多副图片。有四种技术可以提高HTTP的李娜接性能:并行连接,持久连接,管道化连接,复用的连接。

4、并行连接

HTTP允许客户端打开多条连接,并行地执行多个HTTP事务。并行连接可能会提高页面的加载速度,但是并行连接不一定更快。比如带宽不足时,像通过一个28.8kbps的Modem接入互联网,一个连接到速度较快的服务器上的HTTP事务就会很容易耗尽所有可用的带宽。如果并行加载的话,所有对象都会去竞争这有限的带宽,这样每个对象都会以比较慢的速度加载。而且打开大量连接会消耗很多内存资源。实际上,浏览器确实使用了并行连接,但它们会将并行连接的总数限制为一个较小的值。服务器可以随意关闭来自特定客户端的超量连接。

5、持久连接

在事务处理结束后仍然保持打开状态的TCP连接被称为持久连接。重用已对服务器打开的空闲持久连接,可以避开缓慢的连接建立阶段,而且,还可以避免慢启动的拥塞适应阶段,以便更快速地传输数据。

持久连接有两种类型:HTTP/1.0+ “keep-alive”以及HTTP/1.1 ”persistent"

5.1、Keep-alive

keep-alive客户端可以通过包含Connection:Keep Alive首部请求将一条连接保持在打开状态。如果服务器愿意为下一条请求连接保持在打开状态,就在响应中包含相同的首部。

在HTTP/1.0中Keep-alive并非默认使用的,必须随所有希望保持持久连接的报文一起发送。代理或网关必须在将报文转发出去或将其告诉缓存之前,删除在Connection首部中命名的所有首部字段以及Connect首部自身,因为对于哑代理来说,使用Keep-alive会产生问题。

哑代理,或称之为盲中继并不理解Connection首部,而且不知道在沿着转发链路将其发送出去之前,应该将该首部删除。它们只是将字节从一个连接转发到另一个连接上,这就会产生严重的问题。Connection首部是个逐跳首部,只适用于单条传输链路,不应该沿着传输链路向下传输。比如说客户端发送了一个带Keep-alive的请求报文,哑代理收到后直接转发给服务器,服务器收到后会误认为是代理希望进行keep-alive对话,如果它同意的话就会回送一个keep-alive响应。而代理又将这个响应发送给客户端,客户端就会认为代理同意进行keep-alive对话。由于代理不知道keep-alive,所以会将收到的所有数据都回送给客户端,然后等待源端服务器关闭连接,但源端服务器认为代理已经显式地请求它将连接保持在打开状态,所以不会去关闭连接,这样代理就会挂在那里等待连接的关闭。于此同时,客户端收到回送的响应报文时,会立即转向下一条请求,在keep-alive连接上发送,但代理并不认为同一条连接上会有其他请求到来,请求被忽略。这种错误的通信方式会使浏览器一直处于挂起状态,直到客户端或服务器将连接超时,并将其关闭为止。

HTTP/1.1持久连接在默认情况是激活的。要在事务处理结束之后将连接关闭,HTTP/1.1应用程序必须向报文中显式地添加一个Connection:close首部。但是,不发送Connection:close并不意味着服务器承诺永远将连接保持在打开状态。

6、管道化连接

HTTP/1.1允许在持久连接上可选地使用请求管道。在响应到达之前,可以将多条请求放入队列。当第一条请求通过网络流向服务器时,第二条和第三条请求也可以开始发送。但是HTTP客户端必须做好连接会在任意时刻关闭的准备,还要准备好重发所有未完成的管道化请求。同时HTTP客户端不应该用管道化的方式发送会产生副作用的请求(比如POST)