计算机网络-断开连接的四次挥手底层细节

文章目录

  • [1. TCP四次挥手过程](#1. TCP四次挥手过程)
  • [2. 为什么四次挥手中间两次不能变成一次?](#2. 为什么四次挥手中间两次不能变成一次?)
  • [3. 第二次和第三次挥手能合并吗?](#3. 第二次和第三次挥手能合并吗?)
  • [4. 第三次挥手一直没发,会发生什么?](#4. 第三次挥手一直没发,会发生什么?)
  • [5. 第二次和第三次挥手之间主动断开的那端能干什么?](#5. 第二次和第三次挥手之间主动断开的那端能干什么?)
  • [6. 断开连接时,客户端fin包丢失,服务端的状态是什么?](#6. 断开连接时,客户端fin包丢失,服务端的状态是什么?)
  • [7. 为什么四次挥手之后要等2MSL?](#7. 为什么四次挥手之后要等2MSL?)
  • [8. 服务端出现大量的timewait有哪些原因?](#8. 服务端出现大量的timewait有哪些原因?)

1. TCP四次挥手过程

  1. 第一次挥手:客户端发送FIN
  • 客户端打算关闭连接,向服务端发送一个FIN。
  • 状态变化:客户端状态变为FIN-WAIT1。这表示客户端没有数据发送了。但仍然可以接收数据。
  1. 第二次挥手:服务端,发送ACK
  • 服务端接收到FIN后返回一个ACK确认报文。
  • 状态变化:服务端进入CLOSE-WAIT状态。客户端收到确认后进入,FIN-WAIT2状态。
  • 意思:此时处于半关闭状态,服务端可能还有未发完的数据,需要继续发送。
  1. 第三次挥手:服务端发送FIN
  • 当服务端处理完所有数据,准备好关闭连接时,向客户端发送FIN报文段。是。
  • 状态变化。服务端进入LAST-ACK状态。
  1. 第四次挥手:客户端发送ACK
  • 客户端收到FIN后,向服务端发送最后一个ACK确认报文。
  • 状态变化:客户端进入TIME-WAIT状态。服务端收到ACK后,直接进入CLOSE的状态。
  • 最终关闭:客户端在经过2MSL(最大报文生存时间后),自动进入CLOSE的状态。

底层原理:

  • 客户端发送fin包,会携带一个EOF数据。一旦在服务端读取到该符号,read()或recv()就会返回0。
  • 实际操作中,read()==0就是应用程序判断对端已关闭连接的标准信号。
  • 操作系统内核会立刻自动回复一个ACK。
  • 服务端发送的FIN,由应用程序决定什么时候发送。

2. 为什么四次挥手中间两次不能变成一次?

服务器接收到客户端的FIN报文后,内核会返回一个ACK报文,但是服务端应用程序可能还有未发送完的数据,所以并不能立马发送FIN报文。而是将FIN报文的控制权,交给应用程序。

3. 第二次和第三次挥手能合并吗?

当被动关闭方,在TCP挥手过程中,没有数据要发送,并且开启了TCP延迟确认机制,那么第二次和第三次挥手可以合并。

  • TCP延迟确认:收到数据后不立刻发送ack确认包,而是启动一个小定时器,通常最多等两百毫秒。如果等待期间自己正好有数据要发送给对方,就将该ACK合并到数据包里一起发走。

4. 第三次挥手一直没发,会发生什么?

第二次挥手后,主动方会处于FIN-WAIT2状态。就表示主动方发送通道已关闭,等待对方发送FIN报文,关闭对方的发送通道。

这时如果连接是用shutdown函数关闭的,连接可以一直处于FIN-WAIT2状态。因为它可能还可以发送或接收数据。对于close函数关闭的,故而连接由于无法再发送和接收数据,所以这个状态不可以持续太久,而tcp-fin-timeout控制了这个状态下连接时长,默认是六十秒。

5. 第二次和第三次挥手之间主动断开的那端能干什么?

如果主动断开的那一方式调用了shutdown函数来关闭连接的设置。关闭了发送能力,没有关闭接收能力,那么主动断开一方在第二次和第三次挥手之间还可以接收数据。

6. 断开连接时,客户端fin包丢失,服务端的状态是什么?

  • 如果第一次挥手丢失了。那么客户端迟迟收不到对方的AC K的话,也就会触发超时重传机制。重传次数由TCP_ORPHAN_RETRIES参数控制。
  • 当客户端重传FIN报文超过次数后就不会再发送fin报文,而是等待上一次超时重传时间的两倍。如果还没有收到第二次挥手,那么客户端直接进入到CLOSE状态,而服务端还是ESTABLISHE的状态。

7. 为什么四次挥手之后要等2MSL?

MSL是报文在网络中存活最长时间。

  1. 确保沿街的可靠关闭兜底(最后一次ACK丢失)

    为了确保客户端最后发出的ACK能够顺利到达服务端,如果这个ACK丢失,服务端会超时重发。第三次握手的报文2MSL刚好是一个报文,在网络中一来一回最长时间。等待2MSL能确保客户端有足够时间,接收到可能重传的FIN并发送ACK,从而让双方都正常关闭。

  2. 防止历史过期报文干扰新连接

    经过2MSL的时间可以确保本次TCP连接中产生所有报文都在网络中彻底消亡。这样就能避免后续使用相同IP和端口号建立新连接时被就连接的残余报文干扰。

8. 服务端出现大量的timewait有哪些原因?

根本原因:服务端在大量的主动关闭连接。

  1. 大量的短连接
  • 未开启HTTP长连接(keep-Alive),短连接每次请求都要经历这样的过程:建立TCP->请求资源->响应资源->释放连接。
  1. 第二个场景:长连接超时
  • HTTP长连接可以在同一个TCP连接上接收和发送多个HTTP请求/应答,避免了连接建立和释放的开销。
  • Web服务软件一般会提供一个定时器。定时器假如设置时长六十秒,如果客户端在六十秒内都没有再次发起新的请求。定时器时间一到,就会触发回调函数来关闭连接,那么此时服务端上就会出现TIME_WAIT状态的连接。
  1. 第三个场景:HTTP长连接的请求数量达到上限
  • Web服务端通常会有个参数来定义一条HTTP长连接最大能处理请求数量。当超过数量时就会主动关闭连接。
  • 比如nginx的keepalive_requests这个参数,长连接会有一个计数器记录处理请求数量如果超过这个参数,就会主动关闭这个长连接。
  • 该默认值一般为100,但如果是QPS比较高的场景。比如超过一万QPS,甚至更高时,这时候,就会频繁关闭连接,那么此时服务器上就会出现大量的TIME-WAIT的状态。
  • 解决方法调大nginx的keepalive-requests参数。
相关推荐
java叶新东老师2 小时前
解决jetbrains idea 自带终端无法加载windows系统环境变量
java·windows·intellij-idea
大G的笔记本2 小时前
Java WebSocket客户端--java.net.http.HttpClient
java·websocket·.net
我是李龙2 小时前
第二十一章 项目启动与治理架构:从招标到甲乙方协作机制的建立
java·架构·devops
Mem0rin2 小时前
[Java/数据结构]树的基本概念、二叉树的创建和遍历
java·开发语言·数据结构
rannn_1112 小时前
【Redis|高级篇2】多级缓存|JVM进程缓存、Lua语法、多级缓存实现(OpenResty)、缓存同步(Canal)
java·redis·分布式·后端·缓存·lua·openresty
We་ct2 小时前
EventSource & WebSocket & HTTP
前端·javascript·网络·websocket·网络协议·http·面试
Lyyaoo.2 小时前
【JAVA基础面经】CAS 与 ABA
java·开发语言
帐篷Li2 小时前
ONVIF Server 功能完善开发计划
网络·网络协议·http
AC赳赳老秦2 小时前
OpenClaw对接百度指数:关键词热度分析,精准定位博客创作方向
java·python·算法·百度·dubbo·deepseek·openclaw