0%

TCP协议需要三次握手的主要原因


  • 建立连接
    • 什么是连接
    • 为什么要建立连接
  • 为什么要握手三次
    • 解决old duplicated SYN问题
    • 解决ISN协商问题
  • 半连接状态与RST

TCP建立连接阶段,需要进行俗称“三次握手”(three-way handshake)的协商过程。这里就引出两个问题。

  • 为什么TCP需要“三次握手”?
    • 需要解释“三次握手”这个机制的原因
  • 为什么“三次握手”需要三次?
    • 需要解释握手次数的细节

第一个问题的答案很简单,为了在不可靠的IP层上实现可靠性,通信双方需要对通信信息进行初始化和维持特定的状态。状态初始化的协商过程就是握手机制。这里的通信信息包含序号,窗口大小,选项信息等等,正是这些信息保证了TCP的可靠和流量控制的实现。

第二问题答案:通信双方要交换信息,必然是至少需要两次握手的。那么为什么需要第三次握手就是问题的核心。第一,主要是需要防止已失效的旧的SYN请求(old duplicated)再次到达服务端,导致连接错误建立(如初始序号ISN,窗口大小等等)的异常。其次,由于初始序号ISN的特殊性(必须由对方进行校验),必须要第三次握手,才能保证双方ISN交换成功。最后,三次的握手配合RST标志与半连接状态的设计,提供了异常回退,状态重置的可能,是稳定性的体现。

连接与握手机制

这一小节只讨论握手机制,不讨论具体几次握手。

连接与建立连接

TCP的设计目标就是一款可靠的,面向连接的传输层协议。

那什么是连接呢?**连接(connection)**的概念在RFC793文档中是这样暗示的:

The reliability and flow control mechanisms described above require that TCPs initialize and maintain certain status information for each data stream. The combination of this information, including sockets, sequence numbers, and window sizes, is called a connection.

可靠性和流控机制需要在TCP通信双端初始化和维持特定状态信息。这些信息的组合就称为连接,包括双方socket,序号,窗口大小。

因此,连接的建立就是通信双端对上述信息(sockets, seq, wnd)的协商并达到共识的过程。

Since connections must be established between unreliable hosts and over the unreliable internet communication system, a handshake mechanism with clock-based sequence numbers is used to avoid erroneous initialization of connections.

由于连接必须在两个不可靠主机,并且在不可靠的IP体系上建立,所以需要一个基于时钟序号的握手机制来避免错误的连接初始化。

由此看来,握手机制是用来隐藏底层的不可靠性质的。并且,这里提到了一个细节,SYN中的序号是基于时钟的。(为什么TCP的ISN需要随机生成 | Tung7 Note)

为什么是三次

  • 防止旧的已失效的SYN请求,再次到达服务端。
  • ISN同步问题必须需要三次。
  • 三次握手结合半连接设计,能提供状态回退的能力,也能避免服务端接收到SYN请求后就认为新连接建立了,空等数据而浪费资源的情况。

已失效的SYN再次到达

为了两端能够同步序号,窗口大小,第一次和第二次握手是必不可少的,那为什么还需要第三次ACK回应呢?主要是为了防止旧的重复的已失效的SYN请求(客户端重发SYN,那么前一个SYN就是已失效的请求)再次到达服务端,因而产生错误(序号迷惑,窗口迷惑,选项迷惑等等问题)。

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion. To deal with this, a special control message, reset, has been devised. If the receiving TCP is in a non-synchronized state (i.e., SYN-SENT, SYN-RECEIVED), it returns to LISTEN on receiving an acceptable reset.

三次握手的主要(principal)原因就是避免旧的重复的连接初始化所引起的混淆。为了解决这个混淆问题,设计出了reset控制信息(RST标志位)。如果接收方在非同步状态(SYN-SENT, SYN-RECEIVED)接收到了RST报文,接收方就会回退到LISTEN状态。

三次握手(配合半连接状态与RST)可以让连接状态有“回退”的可能,而两次握手是不能达到要求的。由此看来三次握手与半连接(half-open)状态是密不可分的。

下面直接用RFC文档中的原例子说明:

image-20210714224054097

在第3行,一个旧的重复的SYN请求比第二行的SYN先到达TCP B,这是TCP B是无法区分这个SYN请求是不是旧的,只能响应ACK并且状态由LISTEN变为SYN-RECEIVED。TCP A发现TCP B响应回来的报文段中的ACK号不匹配,就直接响应RST=1,让TCP B回退到LISTEN状态。随后在第6行,原本正确的SYN请求到达TCP B后就能正常建立连接。但是如果,原本的SYN请求比RST先到达(也就是第5行和第6行互换),那么就会导致TCP B也响应一个RST。

ISN的交换与验证

A three way handshake is necessary because sequence numbers are not tied to a global clock in the network, and TCPs may have different mechanisms for picking the ISN’s. The receiver of the first SYN has no way of knowing whether the segment was an old delayed one or not, unless it remembers the last sequence number used on the connection (which is not always possible), and so it must ask the sender to verify this SYN. The three way handshake and the advantages of a clock-driven scheme are discussed in [3].

三次握手的另一个必要原因就是为了双方都能正确同步ISN。由于网络不存在一个全局时钟,并且通信双方都有自己的方式得到ISN。接收方是无法判断报文段是否是延误的失效的报文段,除非它记住上一个在连接中使用的序号(这是不可能实现的),所以接收方必须向发送方验证这个SYN。

半连接状态

RST

RST并不是一定有效的,除了在握手阶段,其他情况下RST包的SEQ序号必须在接收窗口中才有效,否则会被忽略掉。

Reset Processing

In all states except SYN-SENT, all reset (RST) segments are validated
by checking their SEQ-fields. A reset is valid if its sequence number
is in the window. In the SYN-SENT state (a RST received in response
to an initial SYN), the RST is acceptable if the ACK field
acknowledges the SYN.

The receiver of a RST first validates it, then changes state. If the
receiver was in the LISTEN state, it ignores it. If the receiver was
in SYN-RECEIVED state and had previously been in the LISTEN state,
then the receiver returns to the LISTEN state, otherwise the receiver
aborts the connection and goes to the CLOSED state. If the receiver
was in any other state, it aborts the connection and advises the user
and goes to the CLOSED state.

参考

  1. tcp - Why do we need a 3-way handshake? Why not just 2-way? - Network Engineering Stack Exchange

  2. rfc793 (ietf.org)