4-6:TCP协议之连接管理机制(三次握手四次挥手详解)

Posted 快乐江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4-6:TCP协议之连接管理机制(三次握手四次挥手详解)相关的知识,希望对你有一定的参考价值。

本文大部分内容来自小林coding《图解网络》,感谢分享,简单整理。

一:TCP三次握手过程和状态变迁

(1)三次握手过程和状态变迁过程详解

TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手完成的。

开始的时候,客户端和服务端都处于CLOSED状态。服务器主动监听某个端口,处于LISTEN状态

客户端会随机初始化序号(client_isn), 将此序号置于TCP首部的【序号】字段中,同时将SYN标志位置为1,表示SYN报文。接着把第一个SYN报文发送给服务端,表示向服务器发起连接,该报文不包含应用层数据,之后客户端就处于了SYN-SENT状态


服务端收到客户端的SYN报文后,服务端也会随机初始化自己的序号(server_isn),将此序号填入TCP首部的【序号】字段中,其次在TCP首部【确认应答号】填入client_isn+1,接着把SYN和ACK标志位置为1,最后把报文发给客户端,该报文也不包含应用程序数据。之后服务端处于SYN-RCVD状态

客户端受到服务端报文后,还要向服务器回应最后一个应答报文。于是将该应答报文TCP首部ACK标志位置为1其【确认应答号】字段填入server_isn+1,最后把报文发送给服务端。此次报文可以携带客户服务器的数据,之后客户端处于ESTABLISHED状态。服务器在收到客户端应答报文后,也进入ESTABALISHED状态

一旦完成三次握手,客户端就都处于了ESTABALISHED状态,此时链连接建立完成,客户端和服务端就可以相互发送数据了。

(2)为什么必须要三次握手?

在讲述之前,我们需要再次回复是什么是TCP连接:

  • 用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket,序列号和窗口大小称为连接

A:只有三次握手才可以阻止重复历史连接的初始化(主要原因)

RFC793指出的TCP连接使用三次握手的主要原因:

Thep principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

意思是:为了防止旧的重复连接初始化造成混乱

网络环境错综复杂,它并不遵循先发先到的原则,有可能新的数据相比旧的数据会先到目标主机,而三次握手可以避免这种混乱

因此在网络拥堵的情况下,一个旧的SYN报文比新的SYN早到了服务端,那么此时服务端会返回一个SYN+ACK报文给客户端,客户端收到后可以根据自身上下文,判断这是一个历史连接,那么客户端会发送RST给服务端,中止此次连接


相反,如果是两次握手,就无法判断是否是历史连接。三次握手则可以在客户端准备发送第三次报文时,能够拥有足够的上下文判断当前是否为历史连接

B:同步双方初始序列号

TCP协议通信的双方,都必须维护一个【序列号】,序列号是可靠传输的关键因素,具体作用

  • 接收方可以去除重复数据
  • 接收方可以根据数据包的序列号按序接受
  • 可以标识发送出去的数据,哪些是已经被对方接收的

所以当客户端发送携带【初始序列号】的SYN报文的时候,需要服务端返回一个ACK应答报文,表示客户端的SYN报文服务端已经成功接收;而当服务端发送【初始序列号】给客户端时,依然也要得到客户端的应答回应。这样一来一回,才能保证双方的序列号可以被可靠同步

四次握手其实也能够可靠的同步初始化序列号,可以把第二步和第三步优化为一步,减少通信次数
前两次握手只保证了一方的初始序列号可以被对方成功接收,没有办法保证双方的初始初始序列号都能被确认接收

C:避免资源浪费

如果仅有两次握手,当客户端的SYN请求在网络中堵塞时,客户端没有接受到ACK,就会触发重传,由于没有三次握手,所以服务端不清楚客户端是否已经收到了自己发送的建立连接的ACK确认,所以每收到一个SYN就先去建立一个连接

这样做的后果很麻烦。如果客户端的SYN堵塞了,重复发送了多次SYN报文,那么服务器在收到SYN后就会建立多个冗余的无效连接,造成资源浪费

同时这也容易受到SYN FIood(SYN洪水攻击)
最后,服务器是一对多的,从上面的叙述中可以看出。不论是几次握手,我们能保证前 n − 1 n-1 n1次是可靠的,但是第n次是谁发谁的,谁就会认为连接建立好了,谁就要承担连接丢失的后果,所以我们肯定尽可能让客户端背锅,否则服务器会产生大量的废弃连接

二:TCP四次挥手过程和状态变迁

TCP断开连接是通过四次挥手的方式进行的,双方都可以断开连接,断开连接后主机资源将会被释放

(1)四次挥手过程和状态变迁详解

具体过程如下

  • 客户端打算关闭连接,此时会发送一个TCP首部FIN标志位置为1的报文,也即FIN报文,之后客户端会进行FIN_WAIT_1状态(应用层close,用户不可能发送数据)
  • 服务端受到该报文后,就像客户端发送ACK应答报文,接着服务端进入CLOSE_WAIT状态
  • 客户端收到服务端的ACK应答报文后,进行FIN_WAIT_2状态
  • 等待服务端处理完数据后,就会向客户端发送FIN报文,之后服务端进行LAST_ACK状态
  • 客户端再收到服务端的FIN报文后,回应一个ACK应答报文,之后进入TIME_WAIT状态
  • 服务端收到了ACK后,进入CLOSED状态,至此服务端完成连接关闭
  • 客户端在经过2MSL后,自动进入CLOSED状态,至此客户端完成连接的关闭


需要注意,主动关闭连接的才会有TIME_WAIT状态

(2)为什么需要四次挥手?

首先关闭连接时,客户端向服务端发送FIN,仅仅表示关闭的是客户端对服务端的单向信道;服务端收到客户端的FIN报文时,先回应一个ACK,表示“你先等等,可能还有数据未处理完”,等服务端不再发送数据时,才发送FIN报文给客户端表示同意现在关闭连接

所以多的那一次一般就是服务端需要等待完成数据的发送和处理,其中的ACK和FIN分开发送了

(3)什么是TIME_WAIT以及为什么TIME_WAIT是2MSL

A:TIME_WAIT

MSL是 M a x i m u m Maximum Maximum S e g m e n t Segment Segment L i f e t i m e Lifetime Lifetime的缩写,意为报文最大生存时间,它是任何报文在网络上存在的最长时间,超过此时间报文将会被丢弃。

  • TCP报文基于IP协议,而且IP头中有一个TTL字段,是IP数据报文可以经过的最大路由数目,每经过一个处理他的路由器此值就会减1,当此值为0时数据报将会被丢弃,同时发送ICMP报文通知源主机。

TIME_WAIT要等待2倍的MSL是因为网络中可能存在来自发送方的数据包,当这些发送方的数据报文被接收方处理之后又会向对方发送响应,所以一来一回需要2倍时间

2MSL的时间是从客户端接收到FIN后发送ACK开始计时的。如果在TIME-WAIT时间内,因为客户端的ACK没有传输到服务器,客户端又接收到了服务器重发的FIN报文,那么2MSL会重新计时

Linux系统中一个MSL是30s、所以Linux系统停在TIME_WAIT的时间为60s
其定义在Linux内核代码里的名称为TCP_TIMEWAIT_LEN

#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT state, about 60 seconds */

B:为什么需要TIME_WAIT

1:防止旧连接的数据包

假设TIME_WAIT没有等待时间或者等待时间过多,会发生什么呢?如下

上图中,由于关闭连接前SEQ=301的报文被延迟了,如果此时有相同端口的TCP连接被复用后,被延长的SEQ=301抵达了客户端,那么客户端有可能会接受这个过期的报文,造成一些严重的问题

所以TCP设计了2MSL的时间,足以让这两个方向上的数据包都自动丢弃,使原来连接的数据包在网络中自然消失,再出现的数据包一定是新建立的。

2:保证连接正确关闭

TIME_WAIT的另一个作用就是等待足够的时间以确保最后的ACK让被动关闭方接收,从而帮助其正确关闭

还是假设TIME_WAIT没有等待时间或过短,此时又会造成什么问题呢?如下

可以看出,如果最后一个ACK报文传输丢失了,因为没有TIME_WAIT或时间过短,此时客户端就会直接进入CLOSE状态,服务端则会一直保持LASE_ACK状态。那么此时当客户端发起建立连接的SYN请求后,服务端就会发送RST给客户端,连接会被中止。

三:实践-理解TIMIE_WAIT状态

以上是关于4-6:TCP协议之连接管理机制(三次握手四次挥手详解)的主要内容,如果未能解决你的问题,请参考以下文章

Java网络原理之连接管理:TCP三次握手和TCP四次挥手

TCP 连接三次握手、四次挥手

网络 之 三次握手&四次挥手 介绍

TCP 协议(包含三次握手,四次挥手)

TCP 协议(包含三次握手,四次挥手)

TCP 协议(包含三次握手,四次挥手)