From bfa3394ad15d2aa97d152b57cde22e6b579c8a4d Mon Sep 17 00:00:00 2001 From: qornwh1 Date: Wed, 4 Mar 2026 16:51:44 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=ED=86=A0=ED=81=B0=20->=20=ED=95=B4?= =?UTF-8?q?=EC=8B=9C=ED=82=A4=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20/=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EA=B4=80=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MMOTestServer/MMOserver/Game/GameServer.cs | 18 +++++----- .../MMOserver/Utils/UuidGeneratorManager.cs | 34 +++++++++++++------ MMOTestServer/ServerLib/Service/ServerBase.cs | 9 +++++ MMOTestServer/ServerLib/Service/Session.cs | 22 ++++++++++-- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/MMOTestServer/MMOserver/Game/GameServer.cs b/MMOTestServer/MMOserver/Game/GameServer.cs index 083855d..ea2a7a3 100644 --- a/MMOTestServer/MMOserver/Game/GameServer.cs +++ b/MMOTestServer/MMOserver/Game/GameServer.cs @@ -85,7 +85,11 @@ public class GameServer : ServerBase { AccTokenPacket accTokenPacket = Serializer.Deserialize(new ReadOnlyMemory(payload)); string token = accTokenPacket.Token; - long hashKey = UuidGeneratorManager.Instance.GetOrCreate(token); + tokenHash.TryGetValue(token, out long hashKey); + if (hashKey <= 1000) + { + hashKey = UuidGeneratorManager.Instance.Create(); + } if (sessions.TryGetValue(hashKey, out NetPeer? existing)) { @@ -102,6 +106,7 @@ public class GameServer : ServerBase if (username == null) { Log.Warning("[Server] 토큰 검증 실패 - 연결 거부 PeerId={Id}", peer.Id); + UuidGeneratorManager.Instance.Release(hashKey); peer.Disconnect(); return; } @@ -110,17 +115,11 @@ public class GameServer : ServerBase } peer.Tag = new Session(hashKey, peer); + ((Session)peer.Tag).Token = token; sessions[hashKey] = peer; + tokenHash[token] = hashKey; pendingPeers.Remove(peer.Id); - if (hashKey <= 1000) - { - // 더미 클라이언트면 에러 - Log.Error("[Server] Dummy 클라이언트가 입니다. 연결을 종료합니다. HashKey={Key} PeerId={Id}", hashKey, peer.Id); - peer.Disconnect(); - return; - } - Log.Information("[Server] 인증 완료 HashKey={Key} PeerId={Id}", hashKey, peer.Id); OnSessionConnected(peer, hashKey); } @@ -152,6 +151,7 @@ public class GameServer : ServerBase { Log.Information("[GameServer] 세션 해제 HashKey={Key} Reason={Reason}", hashKey, info.Reason); } + UuidGeneratorManager.Instance.Release(hashKey); } protected override void HandlePacket(NetPeer peer, long hashKey, ushort type, byte[] payload) diff --git a/MMOTestServer/MMOserver/Utils/UuidGeneratorManager.cs b/MMOTestServer/MMOserver/Utils/UuidGeneratorManager.cs index 1c0ac58..72591e7 100644 --- a/MMOTestServer/MMOserver/Utils/UuidGeneratorManager.cs +++ b/MMOTestServer/MMOserver/Utils/UuidGeneratorManager.cs @@ -1,21 +1,35 @@ -using System.Collections.Concurrent; - namespace MMOserver.Utils; public class UuidGeneratorManager : Singleton { - private long counter = 0; - private readonly ConcurrentDictionary tokenMap = new(); + // 0 ~ 1000 은 더미 클라이언트 예약 범위 + private const long DUMMY_RANGE_MAX = 1000; - // string token → 고유 long ID 변환 (멀티스레드 안전) - // 동일 token은 항상 같은 ID 반환 - public long GetOrCreate(string token) + private readonly object idLock = new(); + private readonly HashSet usedIds = new(); + + // 고유 랜덤 long ID 발급 (1001번 이상, 충돌 시 재생성) + public long Create() { - return tokenMap.GetOrAdd(token, _ => Interlocked.Increment(ref counter)); + lock (idLock) + { + long id; + do + { + id = Random.Shared.NextInt64(DUMMY_RANGE_MAX + 1, long.MaxValue); + } while (usedIds.Contains(id)); + + usedIds.Add(id); + return id; + } } - public bool TryGet(string token, out long id) + // 로그아웃 / 세션 만료 시 ID 반납 + public bool Release(long id) { - return tokenMap.TryGetValue(token, out id); + lock (idLock) + { + return usedIds.Remove(id); + } } } diff --git a/MMOTestServer/ServerLib/Service/ServerBase.cs b/MMOTestServer/ServerLib/Service/ServerBase.cs index c165089..7e52256 100644 --- a/MMOTestServer/ServerLib/Service/ServerBase.cs +++ b/MMOTestServer/ServerLib/Service/ServerBase.cs @@ -36,6 +36,9 @@ public abstract class ServerBase : INetEventListener // peer → hashKey 역방향은 peer.Tag as Session 으로 대체 protected readonly Dictionary sessions = new(); + // Token / HashKey 관리 + protected readonly Dictionary tokenHash = new(); + // 재사용 NetDataWriter (단일 스레드 폴링이므로 안전) private readonly NetDataWriter cachedWriter = new(); @@ -123,6 +126,12 @@ public abstract class ServerBase : INetEventListener // (재연결로 이미 교체된 경우엔 건드리지 않음) if (sessions.TryGetValue(session.HashKey, out NetPeer? current) && current.Id == peer.Id) { + // 더미 클라 아니면 token관리 + if (!string.IsNullOrEmpty(session.Token)) + { + tokenHash.Remove(session.Token); + } + sessions.Remove(session.HashKey); Log.Information("[Server] 세션 해제 HashKey={Key} Reason={Reason}", session.HashKey, disconnectInfo.Reason); OnSessionDisconnected(peer, session.HashKey, disconnectInfo); diff --git a/MMOTestServer/ServerLib/Service/Session.cs b/MMOTestServer/ServerLib/Service/Session.cs index 892c3a6..969b672 100644 --- a/MMOTestServer/ServerLib/Service/Session.cs +++ b/MMOTestServer/ServerLib/Service/Session.cs @@ -4,12 +4,28 @@ namespace ServerLib.Service; public class Session { - public long HashKey { get; init; } - public NetPeer Peer { get; set; } + public string? Token + { + get; + set; + } + + public long HashKey + { + get; + init; + } + + public NetPeer Peer + { + get; + set; + } public Session(long hashKey, NetPeer peer) { HashKey = hashKey; - Peer = peer; + Peer = peer; + Token = null; } }