[图片] 背景 TCP 的三次握手四次挥手,估计大家都听过。但是真的能把每一步说明白的人比较少。我还记得在之前面试的时候被面试官一顿问,然后一脸懵 B... 都是大学没好好上课,这篇文章就跟大家讲讲到底这三握四挥是在搞什么飞机。 三次握手 握手是指的双方进行连接的操作。 [图片] 三次握手(图片来自网络) ## 为什么 ..

谈谈 TCP 的三次握手四次挥手——浅谈 TCP 系列

背景

TCP 的三次握手四次挥手,估计大家都听过。但是真的能把每一步说明白的人比较少。我还记得在之前面试的时候被面试官一顿问,然后一脸懵 B...
都是大学没好好上课😢,这篇文章就跟大家讲讲到底这三握四挥是在搞什么飞机。

三次握手

握手是指的双方进行连接的操作。


三次握手(图片来自网络)
## 为什么是三次握手 #### 确认通信能力 我们要明白,如果需要进行通信,首先需要保证的是双方都具有发信和收信能力。在不知双方能力状态下进行的通信都是无法保证可靠性和通信效率的。那么通信双方如何确认对方的通信能力呢? 1. A 请求 B 进行连接。(B 已确认 B 的收信能力和 A 的发信能力) 2. B 返回 ACK 相应。(A 已确认双方的收发能力) 3. A 返回 ACK 并建立连接。(B 确认双方收发能力) 上面可以看到,至少是进行三次握手,才能确认双方能力。 #### 防止产生脏数据连接 网络通信情况复杂,不可能保证每一消息都能正常到达其目的地。 在 TCP 连接中,TTL 的网络报文的生存时间一般都会比 TCP 的连接超时时间要长。这样就有可能出现一个问题。A 在发送第一次连接请求时,可能网络拥塞,导致数据包未短时间内到达。到达超时时间后,A 又发送了一次连接请求,这次正常进行连接。连接结束断开后,A 的第一次连接请求到达 B,B 返回 ack。如果是两次握手,A 通过当前的状态,直接拒绝 B 的请求,但 B 会单方面认为连接已经建立,实际上并不是...

每一次握手到底是传输了什么?

想知道除了 ip 和端口号,每次传输的信息是什么,我们首先得知道 TCP 传输信息的结构。


TCP 数据包结构(图片来自网络)

第一次握手

客户端此时处于同步状态,即可以建立连接。服务端处于监听状态。

第二次握手

服务端处于SYN接收状态。

第三次握手

客户端处于连接建立状态,服务端收到信息之后也会进入连接建立状态,双方可以进行通信。

四次挥手

TCP 连接在数据传输完成之后需要关闭,不然会一直占用系统资源。TCP 的连接关闭需要四次通信才行,分手也是个麻烦事儿。

为什么四次才能断开连接呢?

分手这件事情,两边都说明白,分别断开即可。但是想要确认对方都要断开,那么一次两次是不够的。


四次挥手(图片来自网络)

我们还是拿 A、B 来举例。假设 A 要主动断开和 B 的连接。

  1. A 发送断开请求。(需要等待 B 的回复,不然 B 未收到消息 就单方面的断开有点不负责任。超时重传)
  2. B 收到请求并回复 A。(B 收到请求后,很伤心,但是没有办法,只能断开连接,但是 B 是被动的接收断开,所以需要通知其应用程序做关闭准备)
  3. B 这边准备完了,通知 A 可以断开了。
  4. A 回复 B,我收到消息了,断开连接吧。

请求发送的信息是什么?

下面是抓包看到的数据
tcpfin.png

关闭由哪方开始?

答案是哪边都可以,无论是客户端还是服务器端,都可以主动发起关闭请求。
发起关闭请求的前提是数据发送完毕,不一定非得等待对方确认完成。

第一次挥手

假设客户端发起关闭请求。那么客户端发完消息后,会进入FIN_WAIT阶段。此处已经无法再发送应用程序消息,只能处理关闭相关信息。

第二次挥手

服务端收到第一次挥手消息后,返回收到消息的 ack。服务端会进入CLOSE_WAIT阶段。
这个阶段是等待关闭阶段,通知应用程序发送剩余数据,处理现场信息,关闭相应资源

第三次挥手

你应该有点好奇为什么第三次挥手和第二次挥手都是同一个服务。第二次主要是一个 ack 响应,第三次主要是一个服务端关闭通知消息。两者目的不同。
等到三次挥手完毕,那么服务端会进入LAST_ACK状态,即等待最后客户端(主动发起关闭的一方)的 ack 确认。

第四次挥手

第四次挥手是主动发起关闭的一方 A,对被动关闭一方 B 的 FIN 消息的确认。
第四次信息发送完成后,A 会进入TIME_WAIT阶段,而不是直接删除套接字。具体原因我们在下面讲。
收到第四次挥手信息后,B 会直接进行关闭操作。

为什么会有 TIME_WAIT?

还是那句话,网络并不是一个理想世界,任何异常情况都有可能发生。
为了保证 TCP 连接能够正常关闭,主动发起关闭方不能直接删除套接字,而是需要经过一段时间等待。这个时间一般是2MSL(Maxumun Segment Lifetime 最大报文生存时间)。
原因如下

举个例子来证明没有TIME_WAIT的情况。

  1. A 断开了,并且删除了套接字。
  2. B 没有收到 A 的最后一次 ack,导致 FIN 重发。
  3. A 重新开启了新的套接字新的连接,但是这个套接字和之前删除的套接字拥有相同的端口号。
  4. B 后来重发的 FIN 会错误的跑到新的套接字,导致 A 开始执行断开操作。

所以TIME_WAIT也是为了防止上面的误删除。

总结

在并发量很高的时候,熟悉 TCP 的原理和参数变得尤为重要。
我们关注的不仅仅是几次握手 几次挥手,也应该关注一些细节,细节决定成败。更应该多问问为什么如此设计,能解决什么问题。

后续

后续主要是与大家分享讨论一下对 TCP 的滑动窗口机制和可靠性保障的理解。如果有时间,可以跟大家分享一下 TCP 的参数等配置相关内容。

  • TCP
    22 引用 • 25 回帖 • 2 关注
  • 网络
    63 引用 • 117 回帖 • 1 关注
回帖   
请输入回帖内容...