知识点编号:011
难度等级:⭐⭐(必掌握)
面试频率:🔥🔥🔥
🎯 一句话总结
Keepalive就像定期问"还在吗?",确保连接没有悄悄断掉!💓
🤔 为什么需要Keepalive?
问题场景:
客户端 ←→ 服务器
(建立连接后,双方都不发数据)
几小时后...
客户端断电了!💀
但是服务器不知道!
服务器还以为连接正常!
结果:
- 服务器资源被占用
- 连接实际已断开
- 发送数据时才发现断了
🎭 Keepalive工作原理
连接空闲时:
服务器 客户端
| |
| (2小时没数据传输) |
| |
| Keepalive探测包 |
|------------------------->|
| |
| ACK(我还在!) |
|<-------------------------|
| |
| ✅ 连接正常 |
如果客户端挂了:
服务器 客户端
| |
| Keepalive探测包 |
|----------❌------------->|(已挂)
| |
| (等待响应...) |
| |
| 超时,再发探测包 |
|----------❌------------->|
| |
| (重复9次,都超时) |
| |
| 💀 连接断开,释放资源 |
📊 Keepalive参数
Linux系统参数
# 1. 空闲多久开始发送Keepalive
/proc/sys/net/ipv4/tcp_keepalive_time
默认:7200秒(2小时)
# 2. 探测包发送间隔
/proc/sys/net/ipv4/tcp_keepalive_intvl
默认:75秒
# 3. 探测包发送次数
/proc/sys/net/ipv4/tcp_keepalive_probes
默认:9次
总时间 = 2小时 + 75秒 × 9 = 2小时11分钟
💻 Java代码示例
启用Keepalive
Socket socket = new Socket("localhost", 8080);
// 启用Keepalive
socket.setKeepAlive(true);
System.out.println("Keepalive enabled: " + socket.getKeepAlive());
// 注意:Java无法设置具体参数(时间、间隔、次数)
// 这些由操作系统控制
应用层Keepalive(推荐)
// TCP Keepalive太长(2小时),实际应用中通常自己实现
public class HeartbeatClient {
private Socket socket;
private ScheduledExecutorService scheduler;
public void start() throws IOException {
socket = new Socket("localhost", 8080);
// 每30秒发送一次心跳
scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
// 发送心跳包
socket.getOutputStream().write("PING\n".getBytes());
System.out.println("发送心跳");
} catch (IOException e) {
System.err.println("连接断开!");
reconnect();
}
}, 0, 30, TimeUnit.SECONDS);
}
private void reconnect() {
// 重连逻辑
System.out.println("尝试重连...");
}
}
// 服务器端
public class HeartbeatServer {
public void handleClient(Socket client) {
new Thread(() -> {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(client.getInputStream())
);
long lastHeartbeat = System.currentTimeMillis();
// 监控心跳
new Thread(() -> {
while (true) {
long now = System.currentTimeMillis();
if (now - lastHeartbeat > 60000) { // 60秒无心跳
System.out.println("客户端超时,关闭连接");
try {
client.close();
} catch (IOException e) {}
break;
}
try {
Thread.sleep(10000); // 每10秒检查一次
} catch (InterruptedException e) {}
}
}).start();
// 接收消息
String line;
while ((line = reader.readLine()) != null) {
if ("PING".equals(line)) {
lastHeartbeat = System.currentTimeMillis();
System.out.println("收到心跳");
} else {
// 处理其他消息
}
}
} catch (IOException e) {
System.err.println("连接异常");
}
}).start();
}
}
🐛 常见面试题
Q1:什么是TCP Keepalive?有什么作用?
答案:
TCP Keepalive是一种检测死连接的机制。
作用:
1. 检测对端是否存活
2. 防止防火墙/NAT超时
3. 及时释放死连接资源
工作原理:
- 连接空闲一段时间后(默认2小时)
- 发送Keepalive探测包
- 如果收到ACK,连接正常
- 如果超时,重传探测包
- 重传多次(默认9次)后仍无响应
- 判定连接断开,释放资源
缺点:
- 默认2小时太长
- 参数由操作系统控制,应用层无法精确控制
- 实际应用中通常自己实现心跳
建议:
应用层自己实现心跳机制(如每30秒一次)
Q2:TCP Keepalive和HTTP Keep-Alive的区别?
答案:
TCP Keepalive:
- TCP层机制
- 检测连接是否存活
- 发送探测包
- 默认2小时触发
- 防止死连接占用资源
HTTP Keep-Alive:
- HTTP层机制
- 连接复用
- 避免频繁建立/关闭连接
- 提高性能
- Connection: keep-alive
完全不同的概念!
一个是"心跳检测"
一个是"连接复用"
记忆:
TCP Keepalive → 保活(检测存活)
HTTP Keep-Alive → 保持(保持连接)
🎓 总结
Keepalive的关键点:
- 作用:检测死连接
- 时间:默认2小时(太长)
- 建议:应用层自己实现心跳
- 区别:不是HTTP Keep-Alive
记忆口诀:
Keepalive心跳包 💓
定期探测还在吗 🔍
默认两小时太长 ⏰
应用层自己实现 ✅
文档创建时间:2025-10-31
作者:AI助手 🤖