MST

星途 面试题库

面试题:Java中如何在Socket编程里简单实现心跳机制

在Java Socket编程环境下,请描述实现一个简单心跳机制的基本思路和关键步骤,并给出核心代码片段示例。
42.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

基本思路

  1. 客户端:定时向服务器发送心跳消息,告知服务器自己处于活跃状态。
  2. 服务器:接收客户端的心跳消息,记录客户端的活跃状态,同时设置一个超时机制,如果在一定时间内没有收到客户端的心跳消息,则判定客户端已断开连接。

关键步骤

  1. 客户端
    • 创建一个定时器,定时发送心跳消息。
    • 建立Socket连接,向服务器发送心跳消息。
  2. 服务器
    • 监听客户端连接,接收心跳消息。
    • 使用一个数据结构(如HashMap)记录客户端的活跃状态。
    • 启动一个线程,定期检查客户端的活跃状态,移除超时的客户端。

核心代码片段示例

客户端

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;

public class HeartbeatClient {
    private static final String SERVER_IP = "127.0.0.1";
    private static final int SERVER_PORT = 12345;
    private static final int HEARTBEAT_INTERVAL = 5000; // 5秒

    public static void main(String[] args) {
        try (Socket socket = new Socket(SERVER_IP, SERVER_PORT);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {

            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    out.println("HEARTBEAT");
                }
            }, 0, HEARTBEAT_INTERVAL);

            // 防止主线程退出
            while (true) {
                Thread.sleep(1000);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

服务器

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class HeartbeatServer {
    private static final int PORT = 12345;
    private static final int TIMEOUT = 10000; // 10秒
    private Map<String, Long> clientLastActiveTime = new HashMap<>();

    public HeartbeatServer() {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("Server started on port " + PORT);

            ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
            executorService.scheduleAtFixedRate(() -> {
                clientLastActiveTime.entrySet().removeIf(entry -> System.currentTimeMillis() - entry.getValue() > TIMEOUT);
                System.out.println("Cleaned up inactive clients. Active clients: " + clientLastActiveTime.size());
            }, 0, 1, TimeUnit.SECONDS);

            while (true) {
                try (Socket clientSocket = serverSocket.accept();
                     BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
                    String clientAddress = clientSocket.getInetAddress().toString();
                    clientLastActiveTime.put(clientAddress, System.currentTimeMillis());
                    System.out.println("Client connected: " + clientAddress);

                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        if ("HEARTBEAT".equals(inputLine)) {
                            clientLastActiveTime.put(clientAddress, System.currentTimeMillis());
                            System.out.println("Received heartbeat from " + clientAddress);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new HeartbeatServer();
    }
}