为什么服务器不能在 TCP 三向握手中发送数据?

网络工程 tcp 协议论 传输协议 第 4 层
2022-02-12 05:28:21

在三路握手中,只有从ACK包我们才能发送数据。为什么服务器不能用 SYN-ACK 包发送数据?我低估了为什么客户端不能向服务器发送数据(例如防止恶意客户端的 SYN 泛洪),但为什么服务器不能发送数据,例如服务器的认证?

据我了解,客户端和服务器都不会出现问题。

从客户端的角度来看,在三向握手中已经知道使用 SYN-ACK 数据包的服务器 ISN,并且它可以毫无问题地创建它的连接(这在三向握手中已经发生)。

从服务器的角度来看,我们不需要在其内核空间上创建接收缓冲区。发送缓冲区也可以有效地减少,例如,如果第二个数据对于所有套接字都是恒定的(例如,服务器的证书和公钥)。

1个回答

理论上,数据可以与 SYN 一起发送,但在连接状态为 ESTABLISHED 之前不应传递给应用程序。引用RFC 793 第 3.4 节 - “建立连接”

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

这意味着客户端和服务器理论上都可以在 SYN 内发送数据。但是只有在收到最终的 ACK 并因此在服务器端达到 ESTABLISHED 时,客户端数据才应该传送到服务器应用程序。而在 SYN+ACK 中来自服务器的数据可以立即传递给客户端,因为一旦收到 SYN+ACK,客户端状态就已建立,从 RFC 中的示例可以看出:

      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN
  2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
  3.  ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED   
  4.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK>       --> ESTABLISHED    
  5.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED

使用 TCP 快速打开,在某些情况下甚至可以消除客户端的限制。

但通常 TCP 握手中不包含任何数据,因为默认的套接字 API 不支持这种用例:只有一个connect在客户端和服务器端进行握手accept,两者都不能在内部传递任何数据握手。