知识点编号:015
难度等级:⭐⭐(掌握)
面试频率:🔥🔥🔥
🎯 一句话总结
RST就像连接的紧急刹车,立即断开,不走四次挥手!🚨
🤔 什么是RST?
正常关闭:四次挥手
客户端 服务器
| FIN |
|---------------------->|
| ACK |
|<----------------------|
| FIN |
|<----------------------|
| ACK |
|---------------------->|
需要4个包,温柔关闭
RST关闭:立即断开
客户端 服务器
| RST |
|---------------------->|
| 💥 连接立即断开! |
只需1个包,暴力关闭
🎭 什么情况下发送RST?
1. 连接不存在
客户端 服务器
| SYN |
|---------------------->|
| | ❌端口未监听
| RST |
|<----------------------|
场景:访问一个没有监听的端口
示例:telnet localhost 9999(9999端口未开)
结果:Connection refused
2. 连接异常终止
// 直接关闭Socket,不走四次挥手
Socket socket = new Socket("localhost", 8080);
socket.setSoLinger(true, 0); // 设置SO_LINGER
socket.close(); // 发送RST,立即断开
// 效果:
// - 不等待发送缓冲区数据
// - 不等待四次挥手
// - 立即发RST断开
3. 接收到异常数据
连接已关闭,但收到数据:
客户端 服务器
| (连接已关闭) |
| 数据包 |
|---------------------->|
| | ❌连接不存在
| RST |
|<----------------------|
场景:
- 服务器重启,连接丢失
- 客户端不知道,继续发数据
- 服务器回复RST
4. 半连接队列满(SYN Flood防御)
SYN攻击时:
攻击者 服务器
| SYN |
|---------------------->|
| | 半连接队列满
| RST |
|<----------------------|
服务器拒绝连接,发送RST
💻 Java代码示例
触发RST
// 方式1:SO_LINGER = 0
Socket socket = new Socket("localhost", 8080);
socket.setSoLinger(true, 0); // 立即发送RST
socket.close(); // 发送RST,不是FIN
// 方式2:连接到未监听的端口
try {
Socket socket = new Socket("localhost", 9999);
} catch (ConnectException e) {
// Connection refused
// 服务器发送了RST
System.out.println("收到RST: " + e.getMessage());
}
// 方式3:在连接关闭后发送数据
Socket socket = new Socket("localhost", 8080);
socket.close();
try {
socket.getOutputStream().write("data".getBytes());
} catch (IOException e) {
// Socket closed
System.out.println("连接已RST");
}
观察RST(使用tcpdump)
# 抓包观察RST
tcpdump -i any port 8080 -nn
# 输出示例:
# 10:00:00.001 IP 192.168.1.1.50000 > 192.168.1.2.8080: ... [SYN]
# 10:00:00.002 IP 192.168.1.2.8080 > 192.168.1.1.50000: ... [RST, ACK]
# ↑ RST标志
# Wireshark过滤器:
tcp.flags.reset == 1
⚠️ RST vs FIN 对比
| 特性 | FIN(正常关闭) | RST(异常关闭) |
|---|---|---|
| 过程 | 四次挥手 | 立即断开 |
| 数据 | 等待发送完 | 丢弃未发送数据 |
| 优雅 | 温柔关闭 | 暴力关闭 |
| 应用 | 知道连接关闭 | 可能收到异常 |
| 包数量 | 4个包 | 1个包 |
生活比喻:
FIN:好聚好散,先把话说完
RST:翻脸不认人,立即挂电话
🐛 常见面试题
Q1:什么是TCP RST?什么情况下会收到RST?
答案:
RST(Reset)是TCP的一个标志位,用于异常终止连接。
收到RST的场景:
1. ✅ 连接不存在
- 访问未监听的端口
- Connection refused
2. ✅ 连接异常关闭
- SO_LINGER = 0
- 程序崩溃
3. ✅ 接收到异常数据
- 连接已关闭但收到数据
- 服务器重启后收到旧连接数据
4. ✅ 防火墙拦截
- 防火墙发送RST拒绝连接
5. ✅ 队列满
- 半连接队列满
- 全连接队列满
特点:
- 立即断开,不走四次挥手
- 丢弃未发送的数据
- 一个包完成断开
应用层表现:
- Java: SocketException
- C: Connection reset by peer
Q2:RST和FIN的区别?
答案:
FIN(正常关闭):
- 四次挥手,温柔关闭
- 等待数据发送完
- 对方知道你要关闭
- 优雅退出
- 适用:正常业务结束
RST(异常关闭):
- 立即断开,暴力关闭
- 丢弃未发送数据
- 对方可能收到异常
- 紧急刹车
- 适用:异常情况、拒绝连接
代码示例:
// FIN
socket.close(); // 默认四次挥手
// RST
socket.setSoLinger(true, 0);
socket.close(); // 发送RST
项目经验:
- 正常退出:用FIN
- 超时/异常:用RST
- 防止TIME_WAIT过多:用RST(谨慎)
🎓 总结
RST的关键点:
- 作用:异常终止连接
- 场景:端口未监听、异常数据、队列满
- 特点:立即断开,丢弃数据
- 对比FIN:暴力 vs 优雅
记忆口诀:
RST紧急刹车 🚨
立即断开不墨迹 ⚡
端口未开会收到 🚫
异常数据也会来 ⚠️
文档创建时间:2025-10-31