关于握手那些事

本贴最后更新于 1595 天前,其中的信息可能已经时过境迁

缘起

可能学习过计算机网络的同学都知道 TCP/IP 在建立连接时需要进行三次握手,但不知大家是否考虑过为何必须用三次握手来建立连接?是否可以通过两次握手就建立?为何中断连接的时候又必须进行四次握手,而不能用三次握手?下边在这篇文章中我们对这些问题一一进行解答。

报文格式

握手建立 TCP 连接的过程,其本质就是连接双方达成传输规则的公式,而规则的达成势必少不了共同的约定。而 TCP 报文便是 TCP 连接建立的共识。因此开始之前先了解 TCP 报文的格式是很有必要的。按照谢希仁老师的教材,TCP 的报文格式如下所示:

上图的字段是很多的,但在此处并不需要我们都了解,其中下边这几个字段和握手过程密切相关,需要我们提前予以说明。

  1. 序号:Seq 序号,占 32 位,用来标识从 TCP 源端向目的端发送的字节流,发起方发送数据时对此进行标记。
  2. 确认号:Ack 序号,占 32 位,只有 ACK 标志位为 1 时,确认序号字段才有效,Ack=Seq+1。
  3. 标志位:共 6 个,即 URG、ACK、PSH、RST、SYN、FIN 等,具体含义如下:
    (A)URG:紧急指针(urgent pointer)有效。
    (B)ACK:仅当 ACK=1 时确认号字段才有效。当 ACK=0 时,确认号字段无效
    (C)PSH:当两个应用进程进行交互通信时,有时一端的应用进行希望在键入一个命令后能够立即受到对方的响应。在这种情况下,TCP 就可以使用推送(PSH)操作。接受放在受到 PSH=1 的报文段后,就会尽快交付给接受应用进程,而不在等到缓存填满之后再发送。
    (D)RST:用于重置连接。当 RST=1 时,表明 TCP 连接中出现了严重差错,必须释放连接,然后重新建立连接
    (E)SYN:在建立连接时用来同步序号。
    (F)FIN:用来释放一个连接。

三次握手

所谓三次握手指的就是 TCP 连接在建立时需要客户端和服务器总共发送 3 个数据包确认连接的建立。整个流程如下所示:

操作 作用
第一次握手 客户端将标志位 SYN 置为 1,随机产生一个值 seq=x,并将该数据包发送给服务器,客服端进入进入 SYN_SENT 状态,等待服务器端确认。 客户端发信服务器收到,此时服务器就会明白,客户端的发信能力和自己的接受能力没有问题
第二次握手 服务器收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器将标志位 SYN 和 ACK 都置为 1,ack=x+1,随机产生一个值 seq=y,并将该数据包发送给客户端以确认连接请求,服务器进入 SYN_RCVD 状态 服务器发信客户端收到,此时客户端就会明白服务器端的发信能力和收信能力都没问题,此时服务器还不知道自己的发信能力和客户端的收信能力如何,因此引入了第三次握手
第三次握手 客户端收到确认后,检查 ack 是否为 x+1,ACK 是否为 1,如果正确则将标志位 ACK 置为 1,ack=y+1,并将该数据包发送给服务器,服务器检查 ack 是否为 y+1,ACK 是否为 1,如果正确则连接建立成功,客户端和服务器进入 ESTABLISHED 状态,完成三次握手,随后客户端与服务器之间可以开始传输数据了。 客户端发信服务器收到信之后,就会明白自己的发信能力和客户端的收信能力都没有问题,两个都会明白彼此之间收发能力都正常。可以进行数据传输 。
到这里可能会有人问了,两次握手之后客户端直接向服务器端直接发送数据,不也可以吗?
严格意义上讲,第二次握手之后,客户端直接发送数据也可以向服务器确定客户端的接受能力和自己的发信能力。但是直接发送的话,可能由于服务器端没有准备就绪,从而造成数据包的丢失,也就是说第三次的握手在一定程度上是提前让服务器做好接受数据的准备。

挥手道别

所谓四次握手就是指终止 TCP 连接的时候,需要客户端和服务器总共发送 4 个数据包以确认连接的断开。整个过程如下图所示:

操作 作用
第一次挥手 客户端发送一个 FIN,用来关闭客户端到服务器的数据传送,客户端进入 FIN_WAIT_1 状态。 客户端发信,服务器端到收信。客户端告知服务器端自己需要发送的数据已经发完,但服务器端不一定全部收到
第二次挥手 服务器收到 FIN 后,发送一个 ACK 给客户端,确认序号为收到序号+1(与 SYN 相同,一个 FIN 占用一个序号),服务器进入 CLOSE_WAIT 状态。 服务器端发信,客户端收信。服务器端告知客户端其发送的数据自己已经全部收到了。但是服务器端不一定数据发送完毕
第三次挥手 服务器发送一个 FIN,用来关闭服务器到客户端的数据传送,服务器进入 LAST_ACK 状态。 服务器端发信,客户端收信。服务器端告知客户端自己需要发送的数据以及发送完。但是客户端不一定收到了所有数据
第四次挥手 客户端收到 FIN 后,进入 TIME_WAIT 状态,接着发送一个 ACK 给服务器端,确认序号为收到序号+1,服务器端进入 CLOSED 状态,完成四次挥手。 客户端发信,服务器端收信。告知服务器端其发送的数据自己已经全部接收到了,双方可以释放连接了

到这里可能大家又有疑问了,为什么 TCP 在建立连接的时候需要三次握手就可以了,而分别的时候却要挥手四次?
这是因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即 close,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送。

小结

到这里可能大家就明白了,TCP 在建立连接时要进行三次主要是为了让双方都明确自身和对方收发能力正常。而 TCP 在断开是进行四次挥手,主要是为了保证收发双方数据都发送完毕,并且对方都完全接收到。

  • 网络
    128 引用 • 177 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...