一次经典的三次握手的过程如下图所示:
三次握手最重要的就是交换彼此的ISN。我们需要重点掌握的是包交互过程中序列号变化的原理。
客户端发送的一个报文段是 SYN 报文,这个报文只有 SYN 标记被置位。该SYN的作用是同步客户端的初始序列号。
SYN报文不占用数据,但是它占用一个序列号(也就是占用1个字节)。下次发送的数据序列号要加1。客户端会随机选择1个数字作为初始序列号。
为什么 SYN 段不携带数据却要消耗一个序列号呢?
不占用序列号的段是不需要确认的(都没有内容确认个啥),比如 ACK 段。SYN报文段需要对方的确认,因此需要占用一个序列号。
关于这一点,可以记住如下的规则:
但凡消耗序列号的报文,一定要对端确认,否则会重传直到指定次数为止。
服务端收到客户端的 SYN 段以后,将 SYN 和 ACK 标记都置位。
该SYN的作用是同步服务端生成的初始序列号。
ACK用于告知发送端之前发送的SYN端已经收到了。
确认号字段指定了发送端下次发送报文的序列号(这里等于客户端的ISN加1)。
与前面类似,SYN+ACK报文虽然没有携带数据,由于它需要被确认,因此也消耗一个序列号。
客户端发送三次握手最后一个 ACK 段,这个 ACK 段用来确认收到了服务端发送的 SYN 段。
因为这个 ACK 段不携带任何数据,且不需要再被确认,这个 ACK 段不消耗任何序列号。
除了交换彼此的初始序列号,三次握手的另外一个重要作用就是交换一些辅助信息,比如最大段大小(MSS)、窗口大小(Win)、窗口缩放因子(WS)等。
三次握手过程的状态变化图如下
对于客户端而言:
对于服务端而言:
CLOSED
状态ESTABLISHED
状态。这时双方可以互相发数据了。TCP 支持同时打开,但是非常罕见,使用场景也比较有限,不过我们还是简单介绍一下。它们的包交互过程是怎么样的?TCP 状态变化又是怎么样的呢?
包交互的过程如下图:
以其中一方为例,记为 A,另外一方记为 B
CLOSED
SYN
给 B,然后进入SYN-SENT
状态ACK
的过程中,收到了 B 发过来的 SYN
,what are you 弄啥咧,A 没有办法,只能硬着头皮回复SYN+ACK
,随后进入SYN-RCVD
握手可以变为四次吗?
其实理论上完全是可以的,把三次握手的第二次的 SYN+ACK 拆成先回ACK包,再发 SYN 包就变成了「四次握手」
与 FIN 包不同的是,一般情况下,SYN 包都不携带数据,收到客户端的 SYN 包以后不用等待,可以立马回复 SYN+ACK,四次握手理论上可行,但是现实中我还没有见过。