HTTP–TCP连接

几乎所有的 HTTP 通信都是由 TCP/IP 承载的,TCP/IP 是全球计算机及网络 设备都在使用的一种常用的分组交换网络分层协议集。客户端应用程序可以打开一 条 TCP/IP 连接,连接到可能运行在世界任何地方的服务器应用程序。

一旦连接建 立起来了,在客户端和服务器的计算机之间交换的报文就永远不会丢失、受损或 失序。

TCP的可靠数据管道
HTTP 连接实际上就是 TCP 连接和一些使用连接的规则。

TCP 为 HTTP 提供了一条可靠的比特传输管道。从 TCP 连接一端填入的字节会从另 一端以原有的顺序、正确地传送出来

比如,你想获取 某网站的信息: http://www.joes-hardware.com:80/power-tools.html

 

上图注:Web 浏览器通过 TCP 连接与 Web 服务器进行交互

 

上图注:TCP 会按序、无差错地承载 HTTP 数据

 TCP流是分段的、由IP分组传送
TCP 的数据是通过名为 IP 分组(或 IP 数据报)的小数据块来发送的。

HTTP 和 HTTPS 网络协议栈:

 

 HTTP 要传送一条报文时,会以流的形式将报文数据的内容通过一条打开的 TCP 连 接按序传输。TCP 收到数据流之后,会将数据流砍成被称作段的小数据块,并将段 封装在 IP 分组中,通过因特网进行传输

每个 TCP 段都是由 IP 分组承载,从一个 IP 地址发送到另一个 IP 地址的。每个 IP 分组中都包括:

? 一个 IP 分组首部(通常为 20 字节);

? 一个 TCP 段首部(通常为 20 字节);

? 一个 TCP 数据块(0 个或多个字节)。

IP 首部包含了源和目的 IP 地址、长度和其他一些标记。TCP 段的首部包含了 TCP 端口号、TCP 控制标记,以及用于数据排序和完整性检查的一些数字值。

保持TCP连接的正确运行
TCP 是通过端口号来保持 所有这些连接的正确运行的。

TCP 连接是通过 4 个值来识别的:

< 源 IP 地址、源端口号、目的 IP 地址、目的端口号 >

这 4 个值一起唯一地定义了一条连接。两条不同的 TCP 连接不能拥有 4 个完全相同 的地址组件值(但不同连接的部分组件可以拥有相同的值)。

 

 上图注:承载 TCP 段的 IP 分组,它承载了 TCP 数据流中的小块数据

用TCP套接字编程
操作系统提供了一些操纵其 TCP 连接的工具。为了更具体地说明问题,我们来看一 个 TCP 编程接口。

对TCP连接进行编程所需的常见套接字接口函数:

 

 TCP 客户端和服务器是如何通过 TCP 套接字接口进行通信的:

 

对TCP性能的考虑
 

HTTP 紧挨着 TCP,位于其上层,所以 HTTP 事务的性能在很大程度上取决于底层 TCP 通道的性能。

HTTP事务的时延
串行 HTTP 事务的时间线:

 

 与建立 TCP 连接,以及传输请求和响应报文的时间相比,事务处理时间可能 是很短的。除非客户端或服务器超载,或正在处理复杂的动态资源,否则 HTTP 时 延就是由 TCP 网络时延构成的。

HTTP 事务的时延有以下几种主要原因。

(1) 客户端首先需要根据 URI 确定 Web 服务器的 IP 地址和端口号。如果最近没有对 URI 中的主机名进行访问,通过 DNS 解析系统将 URI 中的主机名转换成一个 IP 地址可能要花费数十秒的时间 3 。

(2) 接下来,客户端会向服务器发送一条 TCP 连接请求,并等待服务器回送一个请 求接受应答。每条新的 TCP 连接都会有连接建立时延。这个值通常最多只有一 两秒钟,但如果有数百个 HTTP 事务的话,这个值会快速地叠加上去。

(3) 一旦连接建立起来了,客户端就会通过新建立的 TCP 管道来发送 HTTP 请求。 数据到达时,Web 服务器会从 TCP 连接中读取请求报文,并对请求进行处理。因特网传输请求报文,以及服务器处理请求报文都需要时间。

(4) 然后,Web 服务器会回送 HTTP 响应,这也需要花费时间。

这些 TCP 网络时延的大小取决于硬件速度、网络和服务器的负载,请求和响应报文 的尺寸,以及客户端和服务器之间的距离。TCP 协议的技术复杂性也会对时延产生 巨大的影响。

性能聚焦区域
一些会对 HTTP 程序员产生影响的、最常见的 TCP 相关时延, 其中包括:

? TCP 连接建立握手;

? TCP 慢启动拥塞控制;

? 数据聚集的 Nagle 算法;

? 用于捎带确认的 TCP 延迟确认算法;

? TIME_WAIT 时延和端口耗尽。

如果要编写高性能的 HTTP 软件,就应该理解上面的每一个因素

TCP连接的握手时延
建立一条新的 TCP 连接时,甚至是在发送任意数据之前,TCP 软件之间会交换一系 列的 IP 分组,对连接的有关参数进行沟通。如果连接只用来传送少量 数据,这些交换过程就会严重降低 HTTP 的性能:

 

TCP 连接握手需要经过以下3个步骤:

(1) 请求新的 TCP 连接时,客户端要向服务器发送一个小的 TCP 分组(通常是 40 ~ 60 个字节)。这个分组中设置了一个特殊的 SYN 标记,说明这是一个连接请求。

(2) 如果服务器接受了连接,就会对一些连接参数进行计算,并向客户端回送一个 TCP 分组,这个分组中的 SYN 和 ACK 标记都被置位,说明连接请求已被接受

(3) 最后,客户端向服务器回送一条确认信息,通知它连接已成功建立(现代的 TCP 栈都允许客户端在这个确认分组中发送数据。

小的 HTTP 事务可能会在 TCP 建立上花费 50%,或更多的时间

 

延迟确认
由于因特网自身无法确保可靠的分组传输(因特网路由器超负荷的话,可以随意丢 弃分组),所以 TCP 实现了自己的确认机制来确保数据的成功传输。

每个 TCP 段都有一个序列号和数据完整性校验和。每个段的接收者收到完好的段 时,都会向发送者回送小的确认分组。如果发送者没有在指定的窗口时间内收到确 认信息,发送者就认为分组已被破坏或损毁,并重发数据。

由于确认报文很小,所以 TCP 允许在发往相同方向的输出数据分组中对其进行“捎 带”。

延迟确认算法会在一个特定的窗口时间(通常是 100 ~ 200 毫 秒)内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组。如果在那 个时间段内没有输出数据分组,就将确认信息放在单独的分组中传送。

TCP慢启动
TCP 数据传输的性能还取决于 TCP 连接的使用期(age)。TCP 连接会随着时间进行 自我“调谐”,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移 提高传输的速度。这种调谐被称为 TCP 慢启动(slow start),用于防止因特网的突 然过载和拥塞。 TCP 慢启动限制了一个 TCP 端点在任意时刻可以传输的分组数。

Nagle算法与TCP_NODELAY
如果 TCP 发送了大量包含少量数据的分组,网络的性能就会严重 下降。

Nagle 算法(根据其发明者 John Nagle 命名)试图在发送一个分组之前,将大量 TCP 数据绑定在一起,以提高网络效率。

TIME_WAIT累积与端口耗尽
TIME_WAIT 端口耗尽是很严重的性能问题,会影响到性能基准,但在现实中相对 较少出现。

在只有一个客户端和一台 Web 服务器的异常情况下,构建一条 TCP 连接的 4 个值:

其中的 3 个都是固定的——只有源端口号可以随意改变:

客户端每次连接到服务器上去时,都会获得一个新的源端口,以实现连接的唯一性。

即使没有遇到端口耗尽问题,也要特别小心有大量连接处于打开状态的情况,或为 处于等待状态的连接分配了大量控制块的情况。在有大量打开连接或控制块的情况 下,有些操作系统的速度会严重减缓。

 

HTTP连接的处理
Connection首部
HTTP 允许在客户端和最终的源端服务器之间存在一串 HTTP 中间实体(代理、高 速缓存等)。可以从客户端开始,逐跳地将 HTTP 报文经过这些中间设备,转发到源端服务器上去(或者进行反向传输)。

在某些情况下,两个相邻的 HTTP 应用程序会为它们共享的连接应用一组选项。 HTTP 的 Connection 首部字段中有一个由逗号分隔的连接标签列表,这些标签为 此连接指定了一些不会传播到其他连接中去的选项。

比如,可以用 Connection: close 来说明发送完下一条报文之后必须关闭的连接。 Connection 首部可以承载 3 种不同类型的标签:

? HTTP 首部字段名,列出了只与此连接有关的首部;

? 任意标签值,用于描述此连接的非标准选项;

? 值 close,说明操作完成之后需关闭这条持久连接。

如果连接标签中包含了一个 HTTP 首部字段的名称,那么这个首部字段就包含了 与一些连接有关的信息,不能将其转发出去。在将报文转发出去之前,必须删除 Connection 首部列出的所有首部字段。由于 Connection 首部可以防止无意中对 本地首部的转发,因此将逐跳首部名放入 Connection 首部被称为“对首部的保护”。

Connection 首部允许发送端指定与连接有关的选项:
  

 

串行事务处理时延
如果只对连接进行简单的管理,TCP 的性能时延可能会叠加起来。

比如,假设有一 86 连接管理 | 93 个包含了 3 个嵌入图片的 Web 页面。浏览器需要发起 4 个 HTTP 事务来显示此页面: 1 个用于顶层的 HTML 页面,3 个用于嵌入的图片。如果每个事务都需要(串行地建 立)一条新的连接,那么连接时延和慢启动时延就会叠加起来

除了串行加载引入的实际时延之外,加载一幅图片时,页面上其他地方都没有动静 也会让人觉得速度很慢。

串行加载的另一个缺点是,有些浏览器在对象加载完毕之前无法获知对象的尺寸, 而且它们可能需要尺寸信息来决定将对象放在屏幕的什么位置上,所以在加载了足 够多的对象之前,无法在屏幕上显示任何内容。在这种情况下,可能浏览器串行装载对象的进度很正常,但用户面对的却是一个空白的屏幕。

还有几种现存和新兴的方法可以提高 HTTP 的连接性能。

? 并行连接 通过多条 TCP 连接发起并发的 HTTP 请求。

? 持久连接 重用 TCP 连接,以消除连接及关闭时延。

? 管道化连接 通过共享的 TCP 连接发起并发的 HTTP 请求。

? 复用的连接 交替传送请求和响应报文

 

并行连接
HTTP 允许客户端打开多条连接,并行地执行多个 HTTP 事务。

在 这个例子中,并行加载了四幅嵌入式图片,每个事务都有自己的 TCP 连接。

并行连接可能会提高页面的加载速度

包含嵌入对象的组合页面如果能(通过并行连接)克服单条连接的空载时间和带宽 限制,加载速度也会有所提高。时延可以重叠起来,而且如果单条连接没有充分利 用客户端的因特网带宽,可以将未用带宽分配来装载其他对象。

下图显示了并行连接的时间线:
  

 

相关文章