基本思路
- 客户端:定时向服务器发送心跳消息,告知服务器自己处于活跃状态。
- 服务器:接收客户端的心跳消息,记录客户端的活跃状态,同时设置一个超时机制,如果在一定时间内没有收到客户端的心跳消息,则判定客户端已断开连接。
关键步骤
- 客户端:
- 创建一个定时器,定时发送心跳消息。
- 建立Socket连接,向服务器发送心跳消息。
- 服务器:
- 监听客户端连接,接收心跳消息。
- 使用一个数据结构(如
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();
}
}