文章目录
- [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四次挥手过程

- 第一次挥手:客户端发送FIN
- 客户端打算关闭连接,向服务端发送一个FIN。
- 状态变化:客户端状态变为FIN-WAIT1。这表示客户端没有数据发送了。但仍然可以接收数据。
- 第二次挥手:服务端,发送ACK
- 服务端接收到FIN后返回一个ACK确认报文。
- 状态变化:服务端进入CLOSE-WAIT状态。客户端收到确认后进入,FIN-WAIT2状态。
- 意思:此时处于半关闭状态,服务端可能还有未发完的数据,需要继续发送。
- 第三次挥手:服务端发送FIN
- 当服务端处理完所有数据,准备好关闭连接时,向客户端发送FIN报文段。是。
- 状态变化。服务端进入LAST-ACK状态。
- 第四次挥手:客户端发送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是报文在网络中存活最长时间。
-
确保沿街的可靠关闭兜底(最后一次ACK丢失)
为了确保客户端最后发出的ACK能够顺利到达服务端,如果这个ACK丢失,服务端会超时重发。第三次握手的报文2MSL刚好是一个报文,在网络中一来一回最长时间。等待2MSL能确保客户端有足够时间,接收到可能重传的FIN并发送ACK,从而让双方都正常关闭。
-
防止历史过期报文干扰新连接
经过2MSL的时间可以确保本次TCP连接中产生所有报文都在网络中彻底消亡。这样就能避免后续使用相同IP和端口号建立新连接时被就连接的残余报文干扰。
8. 服务端出现大量的timewait有哪些原因?
根本原因:服务端在大量的主动关闭连接。
- 大量的短连接
- 未开启HTTP长连接(keep-Alive),短连接每次请求都要经历这样的过程:建立TCP->请求资源->响应资源->释放连接。
- 第二个场景:长连接超时
- HTTP长连接可以在同一个TCP连接上接收和发送多个HTTP请求/应答,避免了连接建立和释放的开销。
- Web服务软件一般会提供一个定时器。定时器假如设置时长六十秒,如果客户端在六十秒内都没有再次发起新的请求。定时器时间一到,就会触发回调函数来关闭连接,那么此时服务端上就会出现TIME_WAIT状态的连接。
- 第三个场景:HTTP长连接的请求数量达到上限
- Web服务端通常会有个参数来定义一条HTTP长连接最大能处理请求数量。当超过数量时就会主动关闭连接。
- 比如nginx的keepalive_requests这个参数,长连接会有一个计数器记录处理请求数量如果超过这个参数,就会主动关闭这个长连接。
- 该默认值一般为100,但如果是QPS比较高的场景。比如超过一万QPS,甚至更高时,这时候,就会频繁关闭连接,那么此时服务器上就会出现大量的TIME-WAIT的状态。
- 解决方法调大nginx的keepalive-requests参数。