feat : 토큰 -> 해시키 생성 로직 구조 변경 / 토큰 관리 로직 추가

This commit is contained in:
qornwh1
2026-03-04 16:51:44 +09:00
parent c8ce36a624
commit bfa3394ad1
4 changed files with 61 additions and 22 deletions

View File

@@ -85,7 +85,11 @@ public class GameServer : ServerBase
{ {
AccTokenPacket accTokenPacket = Serializer.Deserialize<AccTokenPacket>(new ReadOnlyMemory<byte>(payload)); AccTokenPacket accTokenPacket = Serializer.Deserialize<AccTokenPacket>(new ReadOnlyMemory<byte>(payload));
string token = accTokenPacket.Token; 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)) if (sessions.TryGetValue(hashKey, out NetPeer? existing))
{ {
@@ -102,6 +106,7 @@ public class GameServer : ServerBase
if (username == null) if (username == null)
{ {
Log.Warning("[Server] 토큰 검증 실패 - 연결 거부 PeerId={Id}", peer.Id); Log.Warning("[Server] 토큰 검증 실패 - 연결 거부 PeerId={Id}", peer.Id);
UuidGeneratorManager.Instance.Release(hashKey);
peer.Disconnect(); peer.Disconnect();
return; return;
} }
@@ -110,17 +115,11 @@ public class GameServer : ServerBase
} }
peer.Tag = new Session(hashKey, peer); peer.Tag = new Session(hashKey, peer);
((Session)peer.Tag).Token = token;
sessions[hashKey] = peer; sessions[hashKey] = peer;
tokenHash[token] = hashKey;
pendingPeers.Remove(peer.Id); 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); Log.Information("[Server] 인증 완료 HashKey={Key} PeerId={Id}", hashKey, peer.Id);
OnSessionConnected(peer, hashKey); OnSessionConnected(peer, hashKey);
} }
@@ -152,6 +151,7 @@ public class GameServer : ServerBase
{ {
Log.Information("[GameServer] 세션 해제 HashKey={Key} Reason={Reason}", hashKey, info.Reason); 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) protected override void HandlePacket(NetPeer peer, long hashKey, ushort type, byte[] payload)

View File

@@ -1,21 +1,35 @@
using System.Collections.Concurrent;
namespace MMOserver.Utils; namespace MMOserver.Utils;
public class UuidGeneratorManager : Singleton<UuidGeneratorManager> public class UuidGeneratorManager : Singleton<UuidGeneratorManager>
{ {
private long counter = 0; // 0 ~ 1000 은 더미 클라이언트 예약 범위
private readonly ConcurrentDictionary<string, long> tokenMap = new(); private const long DUMMY_RANGE_MAX = 1000;
// string token → 고유 long ID 변환 (멀티스레드 안전) private readonly object idLock = new();
// 동일 token은 항상 같은 ID 반환 private readonly HashSet<long> usedIds = new();
public long GetOrCreate(string token)
// 고유 랜덤 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);
}
} }
} }

View File

@@ -36,6 +36,9 @@ public abstract class ServerBase : INetEventListener
// peer → hashKey 역방향은 peer.Tag as Session 으로 대체 // peer → hashKey 역방향은 peer.Tag as Session 으로 대체
protected readonly Dictionary<long, NetPeer> sessions = new(); protected readonly Dictionary<long, NetPeer> sessions = new();
// Token / HashKey 관리
protected readonly Dictionary<string, long> tokenHash = new();
// 재사용 NetDataWriter (단일 스레드 폴링이므로 안전) // 재사용 NetDataWriter (단일 스레드 폴링이므로 안전)
private readonly NetDataWriter cachedWriter = new(); 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) 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); sessions.Remove(session.HashKey);
Log.Information("[Server] 세션 해제 HashKey={Key} Reason={Reason}", session.HashKey, disconnectInfo.Reason); Log.Information("[Server] 세션 해제 HashKey={Key} Reason={Reason}", session.HashKey, disconnectInfo.Reason);
OnSessionDisconnected(peer, session.HashKey, disconnectInfo); OnSessionDisconnected(peer, session.HashKey, disconnectInfo);

View File

@@ -4,12 +4,28 @@ namespace ServerLib.Service;
public class Session public class Session
{ {
public long HashKey { get; init; } public string? Token
public NetPeer Peer { get; set; } {
get;
set;
}
public long HashKey
{
get;
init;
}
public NetPeer Peer
{
get;
set;
}
public Session(long hashKey, NetPeer peer) public Session(long hashKey, NetPeer peer)
{ {
HashKey = hashKey; HashKey = hashKey;
Peer = peer; Peer = peer;
Token = null;
} }
} }