TCP为什么需要三次握手而不是两次?

面试的时候遇到一个问题:TCP为什么需要三次握手而不是两次?

网上对此问题的回答不尽相同,主要有两种声音:

1. 因为TCP需要确认通信双方的序列号,所以,A要对B的序列号确认;

2. 防止已经失效的连接请求报文段突然又传到服务端,因而产生错误。

第一条的讨论可以参见 StackExchange

第二条主要来自于谢希仁老师的《计算机网络》,第7版在P239。
书中举了一个例子:A发出的第一个连接请求报文段没有丢失,而是在网络中滞留,以致延迟到连接释放以后的某个时间才到达B,B接收到这个失效的报文段之后,就认为是新的连接请求,于是接受连接请求,分配资源,但是后续A并没有数据发送过来,这样B的资源就白白浪费了。于是,三次握手可以避免这种情况。

面试的时候,我答的就是第二条,面试官反驳说,服务器都会有超时机制,资源的浪费还会被回收,这个不是主要原因。

那什么是主要原因呢?下面说一下我的分析(最后补充面试官的答案)。

首先我依然认为第二条的说法是正确的,因为第二条就是来自 RFC793,原话是这样的:

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

翻译过来就是第二条:防止失效的重复的连接请求造成困扰。

但是,RFC中所表述的重点在:通过三次握手,通信双方能够正确交换序列号并正常通信,而不是造成资源浪费。(有点第一条的味道)。

RFC中举了下面的例子来说明该情况,这也是区别于第一条的本质所在。


      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN

  2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               ...

  3.  (duplicate) ... <SEQ=90><CTL=SYN>               --> SYN-RECEIVED

  4.  SYN-SENT    <-- <SEQ=300><ACK=91><CTL=SYN,ACK>  <-- SYN-RECEIVED

  5.  SYN-SENT    --> <SEQ=91><CTL=RST>               --> LISTEN


  6.              ... <SEQ=100><CTL=SYN>               --> SYN-RECEIVED

  7.  SYN-SENT    <-- <SEQ=400><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED

  8.  ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK>      --> ESTABLISHED

                    Recovery from Old Duplicate SYN
  

在第3行,B接收到了A已经失效的序列号为90的报文段,认为是新的连接请求,于是状态由LISTEN变成了SYN-RECEIVED;

在第4行,A接收到了B对于失效的连接请求的确认,但是注意,在A这边,91这个序列号已经失效了,使用91是无法与B进行通信的,而B的状态在第3行中不是LISTEN了,怎么再次建立连接呢?

在第5行A向B发送了控制位RST(reset)为1的报文段,将连接状态重置,所以B的状态回到了LISTEN;

接着在第6行B接收到序列号为100的连接请求,于是接下来就可以正常进行三次握手。

可以看到,第三次握手不一定会发送正确的ACK报文段,而是有可能重置B的连接状态的。假如没有第三次握手,在有失效连接报文段的情况下,A认为B的确认无效,无法使用91序列号,B却已经建立连接,通信就无法进行下去,所以必须要有第三次握手。

PS:面试官的解释:

A向B第一次发送的报文段可能在网络中滞留,而后A可能发送了一个序列号也一样的报文段,但是第一个报文段先到达B,于是建立连接并对A确认,A也认为连接建立了,但是后续通信的内容可能不是第一个TCP请求计划的那样,双方在数据格式以及加密解密上肯能存在不一致的情况,通信会发生错误。

当时听的时候就感觉有问题(不过当时被唬住了),后来想一想,他的说法完全没有道理,相同的连接请求,完全无法区分,就可以认为是同一个,之后的数据通信是按照最新的连接来的,一定不会产生通信的错误。

posted @ 2020-04-18 12:00  SanjiApollo  阅读(945)  评论(2编辑  收藏  举报