|
@@ -2,48 +2,79 @@ package com.incubator.core.net.ws;
|
|
|
|
|
|
import com.incubator.common.net.Connection;
|
|
|
|
|
|
-import java.util.Map;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
+import java.util.concurrent.*;
|
|
|
|
|
|
/**
|
|
|
- * 请求过滤器
|
|
|
+ * 请求过滤器(高并发优化版)
|
|
|
+ *
|
|
|
+ * 限制玩家的请求频率,防止过于频繁的请求导致服务过载。
|
|
|
*/
|
|
|
public class RequestFilter {
|
|
|
|
|
|
// 存储最近的请求时间戳:<请求唯一标识, 上次请求时间>
|
|
|
- private static final Map<String, Long> requestTimestampMap = new ConcurrentHashMap<>();
|
|
|
+ private static final ConcurrentMap<String, Long> REQUEST_TIMESTAMP_MAP = new ConcurrentHashMap<>();
|
|
|
|
|
|
// 最短间隔时间(单位:毫秒)
|
|
|
private static final long MIN_REQUEST_INTERVAL = 1000; // 1秒
|
|
|
|
|
|
+ // 定期清理任务线程池
|
|
|
+ private static final ScheduledExecutorService CLEANUP_EXECUTOR = Executors.newSingleThreadScheduledExecutor(r -> {
|
|
|
+ Thread thread = new Thread(r);
|
|
|
+ thread.setName("RequestFilter-Cleanup-Thread");
|
|
|
+ thread.setDaemon(true); // 设置为守护线程
|
|
|
+ return thread;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 静态初始化,启动清理任务
|
|
|
+ static {
|
|
|
+ CLEANUP_EXECUTOR.scheduleAtFixedRate(() -> cleanUp(10 * 60 * 1000), 0, 10, TimeUnit.MINUTES);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 检查是否允许处理请求
|
|
|
*
|
|
|
* @param conn 当前玩家连接
|
|
|
- * @param cmd 消息命令号
|
|
|
+ * @param cmd 消息命令号
|
|
|
* @return true 允许处理,false 拒绝处理
|
|
|
*/
|
|
|
public static boolean isAllowed(Connection conn, int cmd) {
|
|
|
String key = generateRequestKey(conn, cmd);
|
|
|
long now = System.currentTimeMillis();
|
|
|
|
|
|
- // 检查上次请求时间
|
|
|
- Long lastRequestTime = requestTimestampMap.get(key);
|
|
|
-
|
|
|
- if (lastRequestTime != null && (now - lastRequestTime < MIN_REQUEST_INTERVAL)) {
|
|
|
- // 请求过于频繁,拒绝处理
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 更新请求时间
|
|
|
- requestTimestampMap.put(key, now);
|
|
|
- return true;
|
|
|
+ // 使用 compute 函数原子更新
|
|
|
+ return REQUEST_TIMESTAMP_MAP.compute(key, (k, lastTime) -> {
|
|
|
+ if (lastTime == null || now - lastTime >= MIN_REQUEST_INTERVAL) {
|
|
|
+ return now; // 更新为当前时间
|
|
|
+ }
|
|
|
+ return lastTime; // 保留旧值,表示频率超限
|
|
|
+ }) == now;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成请求的唯一标识
|
|
|
+ *
|
|
|
+ * @param conn 玩家连接
|
|
|
+ * @param cmd 消息命令号
|
|
|
+ * @return 唯一标识字符串
|
|
|
*/
|
|
|
private static String generateRequestKey(Connection conn, int cmd) {
|
|
|
- return conn + ":" + cmd;
|
|
|
+ return conn.getPlayerId() + ":" + cmd;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清理过期的请求记录,防止内存膨胀
|
|
|
+ *
|
|
|
+ * @param expirationTime 清理阈值,单位毫秒
|
|
|
+ */
|
|
|
+ public static void cleanUp(long expirationTime) {
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ REQUEST_TIMESTAMP_MAP.entrySet().removeIf(entry -> now - entry.getValue() > expirationTime);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 停止清理任务,用于服务关闭时释放资源
|
|
|
+ */
|
|
|
+ public static void shutdown() {
|
|
|
+ CLEANUP_EXECUTOR.shutdownNow();
|
|
|
}
|
|
|
}
|