四次挥手的过程:
(客户端 || 服务器均可主动发起挥手动作。 假设客户端先发起挥手动作(关闭请求)。假设将客户端视为主动方,服务器视为被动方。)
| 第一次挥手 | 第二次挥手 | 第三次挥手 | 第四次挥手 |
From A to B | 客户端 → 服务器 | 服务器 → 客户端 | 服务器 → 客户端 | 客户端 → 服务器 |
状态 | 客户端: ESTABLISHED→ FIN_WAIT1 | 服务器: ESTABLISHED→ CLOSE_WAIT 客户端: FIN_WAIT1→ FIN_WAIT2 | 服务器: CLOSE_WAIT→ LAST_ACK
| 客户端: FIN_WAIT2→ TIME_WAIT(经过时间等待计时器设计的时间之后)→CLOSED 服务器: LAST_ACK→ CLOSED
|
报文名字 | FIN 报文 (连接释放报文段) | ACK 报文 (确认报文段) | FIN 报文 (连接释放报文段) | ACK 报文 (确认报文段) |
发的啥 | FIN = 1 序号:seq = u | ACK = 1 确认号=客户端初始序列号(ISN)+ 1: ack = u + 1, seq = v | FIN = 1, ACK = 1 确认号ack = u + 1, seq = w | ACK = 1 确认号ack = w + 1, seq = u + 1 |
啥意思 | FIN == Finish 表示它(客户端)不再发送任何数据 | ACK == Acknowledge 通知对方(客户端):你方的发送通道已经关闭 | FIN == Finish 表示它(客户端)不再发送任何数据 | ACK == Acknowledge 通知对方(客户端):你方的发送通道已经关闭 |
发送通道是否关闭 |
| 主动方收到ACK报文,状态由FIN_WAIT1→ FIN_WAIT2,主动方的发送通道关闭。 | 主动方收到FIN报文,内核自动回复ACK报文,连接状态由FIN_WAIT2→ TIME_WAIT,Linux系统下大约1min后TIME_WAIT状态的连接才会彻底关闭。 | 被动方收到ACK报文,连接关闭。 |
关于TIME_WAIT状态的几个问题:
为什么主动方要TIME_WAIT(经过时间等待计时器设计的时间之后)→ CLOSED ?
因为主动方向被动方发送ACK报文,被动方在没有收到ACK报文之前还处于LAST_ACK状态,如果主动方发送的此ACK报文没有到达被动方,被动方会重发FIN报文。
如果主动方不保留TIME_WAIT状态,直接从TIME_WAIT到CLOSED状态,此时主动方连接的端口恢复自由身,可以创建新的连接了。然而被动方的FIN报文可能再次到达(网络中的路由器重复发送的 || 被动方未收到tcp_orphan_retries参数重发的),这样正常通讯的新连接就可能被重复发送的FIN报文误关闭。因此,保留TIME_WAIT状态可以应付重发的FIN报文。
TIME_WAIT状态过多怎么办?
TIME_WAIT状态如果过多就会占用系统资源。
解决办法?
• 修改TIME_WAIT连接状态的上限值
• 启动快速回收机制
• 开启复用机制
• 修改短连接为长连接方式
• 由客户端来主动断开连接