why tcp three way handshake - yaokun123/php-wiki GitHub Wiki

为什么 TCP 建立连接需要三次握手

一、TCP中的连接是什么?

连接:用于保证可靠性和流控制机制的信息,包括Socket、序列号以及窗口大小。
所以,建立 TCP 连接就是通信的双方需要对上述的三种信息达成共识。

Socket:连接中的一对 Socket 是由互联网地址标志符和端口组成的
窗口大小:窗口大小主要用来做流控制
序列号:序列号是用来追踪通信发起方发送的数据包序号,接收方可以通过序列号向发送方确认某个数据包的成功接收。

二、历史连接(通过三次握手才能阻止历史的重复连接的初始化)

为了阻止历史的重复连接的初始化造成的混乱问题,防止使用 TCP 协议通信的双方建立了错误的连接。

如果通信双方的通信次数只有两次,那么发送方一旦发出建立连接的请求之后它就没有办法撤回这一次请求,
如果在网络状况复杂或者较差的网络中,发送方连续发送多次建立连接的请求,
如果 TCP 建立连接只能通信两次,那么接收方只能选择接受或者拒绝发送方发起的请求,
它并不清楚这一次请求是不是由于网络拥堵而早早过期的连接。

所以,TCP 选择使用三次握手来建立连接并在连接引入了 RST 这一控制消息,
接收方当收到请求时会将发送方发来的 SEQ+1 发送回接收方,这时由发送方来判断当前连接是否是历史连接

1、如果当前连接是历史连接,即 SEQ 过期或者超时,那么发送方就会直接发送 RST 控制消息中止这一次连接;
2、如果当前连接不是历史连接,那么发送方就会发送 ACK 控制消息,通信双方就会成功建立连接;

使用三次握手和 RST 控制消息将是否建立连接的最终控制权交给了发送方,因为只有发送方有足够的上下文来判断当前连接是否是错误的或者过期的,这也是 TCP 使用三次握手建立连接的最主要原因。

三、初始序列号

另一个使用三次握手的重要的原因就是通信双方都需要获得一个用于发送信息的初始化序列号,
作为一个可靠的传输层协议,TCP 需要在不稳定的网络环境中构建一个可靠的传输层,
网络的不确定性可能会导致数据包的缺失和顺序颠倒等问题,常见的问题可能包括:

1、数据包被发送方多次发送造成数据的重复;
2、数据包在传输的过程中被路由或者其他节点丢失;
3、数据包到达接收方可能无法按照发送顺序;

为了解决上述这些可能存在的问题,TCP 协议要求发送方在数据包中加入『序列号』字段,有了数据包对应的序列号,我们就可以:
1、接收方可以通过序列号对重复的数据包进行去重;
2、发送方会在对应数据包未被 ACK 时进行重复发送;
3、接收方可以根据数据包的序列号对它们进行重新排序;

序列号在 TCP 连接中有着非常重要的作用,初始序列号作为 TCP 连接的一部分也需要在三次握手期间进行初始化,由于 TCP 连接通信的双方都需要获得初始序列号,所以它们其实需要向对方发送 SYN 控制消息并携带自己期望的初始化序列号 SEQ,对方在收到 SYN 消息之后会通过 ACK 控制消息以及 SEQ+1 来进行确认。

四、通信次数

当我们讨论 TCP 建立连接需要的通信次数时,我们经常会执着于为什么通信三次才可以建立连接,而不是两次或者四次;
讨论使用更多的通信次数来建立连接往往是没有意义的,因为我们总可以使用更多的通信次数交换相同的信息,
所以使用四次、五次或者更多次数建立连接在技术上都是完全可以实现的。
这种增加 TCP 连接通信次数的问题往往没有讨论的必要性,我们追求的其实是用更少的通信次数(理论上的边界)完成信息的交换,
也就是为什么我们在上两节中也一再强调使用『两次握手』没有办法建立 TCP 连接,使用三次握手是建立连接所需要的最小次数。