三次握手

状态位:

  • SYN:请求连接。
  • ACK:应答报文。
  • RST:重新、中断连接。
  • FIN:断开连接。

图文过程:



整体描述:

  1. 一开始,客户端和服务端都处于CLOSED(关闭)的状态。先是服务端主动监听某个端口,处于LISTEN(监听)状态。
  2. 然后客户端主动发起连接SYN,以后处于SYN_SENT(发送SYN)状态。
  3. 服务端收到发送的连接,返回SYN+ACK,之后处于SYN_RCVD状态。
  4. 客户端收到服务端发送的SYN+ACK,发送ACK,之后处于established(已建立)状态。
  5. 服务端收到ACK之后,也处于established(已建立)状态。

这里重点记住一下状态的变化,之前就一直没有特意关注,面试问到就蒙住了。


分析三次握手的原因:

  • 防止旧的重复连接初始化造成混乱


主要是通过第三次握手:客户端通过上下文比较,判断自己期望收到的ACK Num是否是历史连接(序列号超时或者过期)。从而发送RST中断重新连接还是发送ACK连接建立。

  • 同步双方初始序列号
  • 防止建立多个冗余无效链接,造成不必要的资源浪费


三次握手期间的异常

第一次握手丢失

  • 客户端发送SYN,进入SYN_SENT状态;迟迟收不到SYN_ACK,也就是第一次握手丢失,会触发超时重传机制;
  • 客户端会重发SYN报文,每次超时重传时间是上次的2倍;达到最大重传次数后,任务响应就会断开TCP连接

第二次握手丢失

服务端发送SYN-ACK进入SYN_RCVD状态,客户端迟迟没有收到SYN_ACK;会触发两端都超时重传机制;

包含两部分:

  • ACK:客户端迟迟没有收到第二次握手的ACK报文,觉得可能是自己发送的SYN丢失,于是触发超时重传SYN报文
  • SYN:服务端迟迟没有收到第三次握手的ACK报文,觉得可能是自己发送的SYN丢失,于是触发超时重传SYN_ACK报文

第三次握手丢失

  • 客户端发送ACK,进入ESTABLISH状态,服务端迟迟没有收到ACK;会触发超时重传SYN_ACK报文。


四次挥手

图文过程:



整体描述:

  1. 客户端打算关闭连接,此时会发送一个FIN报文(TCP首部FIN标志位被置为1的报文),之后客户端进入FIN_WAIT_1状态。
  2. 服务端收到该报文后,就向客户端发送ACK应答报文,之后服务端进入CLOSE_WAIT状态。
  3. 客户端收到服务端的ACK应答报文,之后进入FIN_WAIT_2状态。
  4. 等待服务端处理完数据之后,服务端发送FIN报文,之后进入LAST_ACK状态。
  5. 客户端收到服务端的FIN报文之后,发送ACK应答报文,之后进入TIME_WAIT状态。
  6. 服务端收到ACK应答报文后,就进入了CLOSED状态,至此服务端完成了连接的关闭。
  7. 客户端在经过2MSL(报文最大存活时间),自动进入CLOSED状态图,至此客户端也完成了连接的关闭。

补充:

  • 主动关闭连接的,才会有TIME_WAIT状态。因为需要等待另一方是否接受到ACK,如果没有接收到另一方就会一直处于LAST_ACK状态。之后2msl(已有的ACK发送时间+)等待另一方的重传FIN报文。
  • 服务端通常需要等待完成数据的发送和处理,所以服务端的ACK、FIN一般都会分开发送,因此会比三次握手多了一次。
  • 2MSL:是从客户端收到FIN后发送ACK开始计时的。

为什么需要TIME_WAIT?

  • 防止旧链接的数据包


  • 当关闭发送的报文被网络延迟了。等到这个TCP被复用后,被延迟的报文抵达并被接受这个过期的报文,造成数据错乱等严重的问题。
  • 经过2MSL时间之后,足以让两个方向的数据包被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接产生的。

  • 保证连接的正常关闭

等待足够的时间以确保最后的ACK能够让被动关闭方接受,从而帮助其正常关闭。
  • 服务端正常收到四次挥手的最后一次ACK报文,则服务端正常关闭连接。
  • 服务端没有收到四次挥手的最后一次ACK报文,则会重发FIN关闭连接报文并等待新的ACK报文。

如果TIME_WAIT时间过短、或者没有,一旦最后的ACK报文丢失,客户端就直接进入关闭状态,而客户端则一直处于LAST_ACK状态。当重新连接的时候,客户端发送SYN请求报文之后,服务端会发送RST报文中断,连接会被终止。