|
|
@@ -0,0 +1,63 @@
|
|
|
+package com.fs.live.websocket.config;
|
|
|
+
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import javax.websocket.Session;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
+import java.util.concurrent.CopyOnWriteArraySet;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 直播间WebSocket连接管理器
|
|
|
+ * 核心:按直播间ID分组存储Session,线程安全,低锁竞争
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class WebSocketSessionManager {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 存储结构:直播间ID -> 该直播间的所有连接Session
|
|
|
+ * CopyOnWriteArraySet:读多写少场景,线程安全且遍历无锁
|
|
|
+ */
|
|
|
+ private static final Map<String, Set<Session>> ROOM_SESSIONS = new ConcurrentHashMap<>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加连接(绑定直播间)
|
|
|
+ */
|
|
|
+ public void addSession(String roomId, Session session) {
|
|
|
+ // 不存在则创建空集合(ConcurrentHashMap的原子操作)
|
|
|
+ ROOM_SESSIONS.computeIfAbsent(roomId, k -> new CopyOnWriteArraySet<>()).add(session);
|
|
|
+ log.info("直播间[{}]新增连接,当前连接数:{}", roomId, ROOM_SESSIONS.get(roomId).size());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 移除连接(清理无效连接)
|
|
|
+ */
|
|
|
+ public void removeSession(String roomId, Session session) {
|
|
|
+ if (ROOM_SESSIONS.containsKey(roomId)) {
|
|
|
+ Set<Session> sessions = ROOM_SESSIONS.get(roomId);
|
|
|
+ sessions.remove(session);
|
|
|
+ // 直播间无连接时清空,释放内存
|
|
|
+ if (sessions.isEmpty()) {
|
|
|
+ ROOM_SESSIONS.remove(roomId);
|
|
|
+ }
|
|
|
+ log.info("直播间[{}]移除连接,当前连接数:{}", roomId, sessions.size());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取直播间所有连接
|
|
|
+ */
|
|
|
+ public Set<Session> getRoomSessions(String roomId) {
|
|
|
+ return ROOM_SESSIONS.getOrDefault(roomId, new CopyOnWriteArraySet<>());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有直播间ID
|
|
|
+ */
|
|
|
+ public Set<String> getAllRoomIds() {
|
|
|
+ return ROOM_SESSIONS.keySet();
|
|
|
+ }
|
|
|
+}
|