📜  什么是 TCP 快速打开?

📅  最后修改于: 2022-05-13 01:57:02.062000             🧑  作者: Mango

什么是 TCP 快速打开?

TCP 握手需要一个完整的 RTT(往返时间)。 RTT 是数据包从发送方到达接收方并返回的时间。一个 RTT 对于“短期”和“时间敏感”流量(例如 Web 流量)来说是大量时间;在浏览器上浏览网页就像访问网站一样。如果传播延迟非常高(例如,地面站和卫星之间的链路)或移动网络非常慢,则性能会进一步下降。一个 RTT 不会(显着)降低“弹性流量”(例如文件传输)的性能,因为一个 RTT 的开销相对于整个连接的持续时间来说相当小。

让我们假设 1 RTT = 86 毫秒。这意味着如果用户正在访问www.xyz.com ,并且仅使用 86 毫秒来建立与XYZ 的服务器的连接。每次用户想要访问同一个服务器时,86 毫秒都会以同样的方式浪费掉。当有文件传输或应用程序更新时,这个 RTT 没什么大不了的,因为这些过程通常需要几分钟或几小时的时间,几分钟前几毫秒不算什么。

什么是 TFO?

TFO 代表TCP 快速打开。它是一种传输层解决方案,用于避免客户端和服务器之间的完整 RTT。它避免了重复连接的 TCP-3 方式握手。 TFO 由 Google 的一个团队提出并在 RFC 7413 中进行了描述。

在正常的 TCP 连接中,一个 RTT 浪费在连接建立中,然后从第三个数据包开始真正的通信开始。 TFO 表示客户端可以在第一个数据包本身中发送 GET 请求,而不会浪费 1 个 RTT。但是这样做有一些条件:

1.不能是“新”连接

由于需要加密 cookie,TFO 仅适用于重复连接。当客户端第一次与服务器交互时,它必须执行 3 次握手。在该握手中,服务器与客户端共享一个加密 cookie。对于下一个连接,客户端只是在 SYN 数据包本身中搭载 GET 请求和 cookie。然后服务器使用 cookie 对客户端进行身份验证,接受连接请求并在 ACK 数据包中发送数据。

2. SYN 包捎带的数据总量必须在规定的范围内。

规定的限度是多少? IPv4 的数据包中总共可以搭载 1460 个字节。因此,一个段的大小变为 1460 B。

3.使用 TFO 只能发送特定类型的 HTTP 请求

支持 GET 请求。 TFO 不支持 POST 请求,因为如果它允许在服务器上进行写入操作,那么黑客就可以执行可能对服务器造成严重损害的恶意活动。

TFO的工作:

TCP Client 和 Server 都必须支持 TFO 才能使用它。现在问题来了,客户端和服务器如何让对方知道他们支持 TFO?答案在于 TCP 标头。

TCP 标头中的“选项”字段用于 TFO。

  • TCP 客户端使用它来请求 TFO Cookie
  • TCP 服务器使用它来发送 TFO Cookie

在选项字段中, Kind变量存储 cookie 的值 32。 cookie 的长度为 16 个字节。当客户端向服务器发送 SYN 数据包时,它会在选项字段中设置Kind = 32 。当服务器看到 kind 值等于 32 时,它就知道客户端支持 TFO 并请求 cookie。服务器生成一个唯一的 cookie,并使用客户端的 IP 地址对其进行加密,以便每个客户端都有一个唯一的 cookie。在选项字段中,服务器将 cookie 发送到客户端。

因此,使用选项字段客户端和服务器让彼此知道他们支持 TFO 并共享 cookie。

TFO 是否支持条件 GET 请求?

它应该支持条件 GET。 GET 请求基本上是只读操作。因此,他们应该得到 TFO 的许可。不应该从时间延迟的角度来看。当本地服务器上的数据陈旧且无法提供给客户端时,条件 GET 请求基本上是从本地服务器发送到中央服务器的。在这种情况下,从中央服务器获取新数据并缓存到本地服务器以服务本地客户端。

Linux命令行:

通过使用一些命令在 Linux 内核中使用 TFO:

检查 Linux 内核中 TFO 的默认设置

$ sysctl net.ipv4.tcp_fastopen

预期输出(这意味着客户端上启用了 TFO):

$ net.ipv4.tcp_fastopen = 1

如果您的机器是服务器,则启用 TFO

$ sudo sysctl -w net.ipv4.tcp_fastopen=2

预期输出:

$ net.ipv4.tcp_fastopen = 2

如果您的机器既是客户端又是服务器,则启用 TFO

$ sudo sysctl -w net.ipv4.tcp_fastopen=3

预期产出

$ net.ipv4.tcp_fastopen = 3

禁用 TFO

$ sudo sysctl -w net.ipv4.tcp_fastopen=0

预期产出

$ net.ipv4.tcp_fastopen = 0