为什么在 TCP 连接中需要来自发起方的 ACK?

网络工程 通讯协议 第4层
2021-07-31 07:45:58

问题不是此链接的副本正如那问为什么我们需要三向握手一样,我知道为什么!我的问题是为什么下面的协议包(PSH ACK)不能容纳ACK包。

我明白为什么需要握手,但我们最终需要来自发起方的 ACK 吗?让我们举一个 http 查询的例子,然后是 TCP 握手。

CLIENT:23434 SN 0 -----> SERVER:80 -- SYN
CLIENT:23434 <----- SERVER:80 SN 0, AN 1 -- SYN ACK
CLIENT:23434 SN 1 AN 1 -----> SERVER:80 -- ACK
CLIENT:23434 SN 1 AN 1 -----> SERVER:80 -- PSH ACK(HTTP GET)

现在如果有一个协议(数据)包,后面跟着一个具有相同序列号和确认号的三路握手的ACK,为什么有ACK包为什么不只使用协议包来同步呢?

3个回答

很好的问题。我同意这不是另一个的重复。

三向握手的目标是建立双向通信通道该通道发生的通信超出了 TCP 的范围。

有时,会为客户端建立连接以向服务器发送某些内容。其他时候,为服务器建立连接以向客户端发送内容。TCP 必须考虑这两种情况。

为简单起见重新引用您的通信插图并添加行号:

#1   SN 0 -----> SERVER:80 -- SYN
#2   <----- SERVER:80 SN 0, AN 1 -- SYN ACK
#3   SN 1 AN 1 -----> SERVER:80 -- ACK
#4   SN 1 AN 1 -----> SERVER:80 -- PSH ACK(HTTP GET)

如果使用 TCP 的协议的行为类似于 HTTP,其中连接建立后的第一个数据传输是Client 向 Server 发送数据,那么您可以说单独的 ACK(第 3 行)似乎是多余的。紧随其后的数据包(第 4 行)足以告诉服务器客户端收到了他们的 ISN(来自第 2 行)。

然而,并非所有协议的行为都像 HTTP——有些协议意味着服务器在连接建立后立即发送数据在这些情况下,服务器必须等待客户端发送空确认包,然后才能获得双向通信通道已成功建立并且可以开始数据传输的肯定确认。

这在网上比较少见,但确实存在。顺便说一句,我可以想到被动 FTP,客户端发起数据连接(也就是发送初始 SYN),但连接的目的是让服务器发送初始数据包——一旦数据连接就开始成立。

TCP 不能对某些协议以一种方式运行,而对其他协议以另一种方式运行。因此,必须发送空确认以便考虑这两种情况。

听起来你在问为什么,如果客户端首先发送数据,客户端不能将裸握手确认与该数据结合起来。

但我认为它可以 - 它通常不会这样做。操作系统 API 是典型的原因......当套接字未处于已建立状态时,它通常不会接受要 write()n 的数据,并且内核在看到 Syn/ack 时不会等待查看如果用户空间在发送 ack 之前发送了一些数据。(因为内核不知道这个双向连接的哪一端先写 - 另一端在完成握手之前不能写)。

如果此时系统确实在握手的第三部分发送了数据,与这种传统相反,他们很可能会发现这样做时存在互操作问题......因此尝试推动信封是不利的。

是的,需要一个空的ack来确认另一端发送的syn

(closed) A <syn>----------> B (listen) 
(syn-sent) A <------------<syn><ack> B (listen) 
(established) A               B (syn-sent)

在这些步骤之后,B 正在等待 A 对 SYN 的 ACK,以达到连接建立状态。

但是你在这里讨论的有趣案例是最小化下一步的可能性

  (established) A <ack>-----------> B (syn-sent)
  (established) A [data>]<ack>-----------> B (established)

 (established) A [<data>]<ack>-----------> B (syn-sent)

但似乎,B 处于非建立状态,它似乎不接受有效载荷

在 RFC 793(第 3.4 节。建立连接)

下面是连接启动的几个示例。尽管这些示例没有显示使用数据承载段的连接同步,但这是完全合法的,只要接收 TCP 在明确数据有效之前不将数据传送给用户(即,数据必须被缓冲)在接收方直到连接达到 ESTABLISHED 状态)

所以从 rfc 看来

4 SN 1 AN 1 -----> SERVER:80 -- PSH ACK(HTTP GET)

将被缓冲,并且只有在它之后的空确认之后才会被传递给应用程序

您的解决方案可能适用于称为延迟确认的实现