这是一个老生常谈的问题,我想从另一个角度说一说我对这种常见问题的理解。

为什么需要3次握手? Link to heading

实际上,三次握手要达成什么目的呢?为什么不能是两次,为什么不能不握手?为什么是三次,而不是四次?

我们从本质上来看这个问题。

为什么需要握手? Link to heading

我们对于这个问题需要有一些非线性的思考。

首先是关于网络和 TCP 的几个事实。

  1. 我们的局限于 TCP 的常规实现下讨论这个问题。

    因为实际上某些协议根本不需要握手。

  2. TCP 由于是流协议,重组等逻辑的存在,势必导致维持连接要付出内存消耗的代价。

  3. 实际上网络包是可以伪造的。也就是对于一个网络请求的发送端的IP,事实上任何人可以随意填充。就像是我发送一个快递到杭州,寄件人却可以写成是你。

因此,TCP 节点需要确保对端是确实在网络中存在的,因此需要“对方可以通过邮寄网络收得到我的回复,并且确认要生成连接”。就像比如上文我寄的快递,如果杭州的收件人用寄件人地址发回一个确认函让你确认一下,就可以避免其他人无意的干扰或者恶意的伪造。这样信息的传递就势必要一来一回。

TCP 通信的目标是点对点,那么两个对端都需要确认是确实存在的,那么势必从逻辑上需要4次一来一回。

这是我们的第一个结论。那么能不能优化?我们已经知道了可以优化成3次握手了。这是为什么呢?

很简单,这就是我们平常在信件中借钱的行为。

A:“你好,我是A,我要借200元” (一天后)

B:“借给你没问题,但你那边的地址是你本人吗?又或者我的后续催款信件你不会收不到吧?我得试试往你寄件人地址发一封” (一天后)

A:“是我。能收到信息,可以证明之前的借钱信息的确我发的了吧?后续也能联系到我。”

因为不是 TCP 的教程,就直接说了,实际上就是把 ACK 和 SYN 一起发。当然除了确认存在,还需要交换序列号。这里我们不展开说了。

为什么会是四次挥手? Link to heading

首先提到挥手,我们说了,握手的时候实际上就是4次,挥手实际上也要确认双方都有意愿挥手。所以是4次。

ok,为什么不能优化为3次呢? 事实上,我们平常说为什么是四次挥手,常常强调的点是,挥手为什么不是3次而是四次。

这非常简单,也是 Socket 编程中的一个小细节。对端要求关闭连接后,实际上 Linux 内核无法判断对应的应用层是否需要立刻关闭(因为TCP允许半开)。因此,需要把这个问题抛给上层去决策,所以操作系统会立刻给对端返回 ACK,但是 FIN 却必须等待应用知道对端已经关闭,调用 close 的时候才能发送。