💓 TCP Keepalive:连接的"心跳包"

25 阅读3分钟

知识点编号: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的关键点:

  1. 作用:检测死连接
  2. 时间:默认2小时(太长)
  3. 建议:应用层自己实现心跳
  4. 区别:不是HTTP Keep-Alive

记忆口诀

Keepalive心跳包 💓
定期探测还在吗 🔍
默认两小时太长 ⏰
应用层自己实现 ✅

文档创建时间:2025-10-31
作者:AI助手 🤖