fix: MMO 서버 버그 수정 및 안정성 개선 (20건)
- VerifyTokenAsync 인증 우회 차단 (빈 문자열→null 반환) - HandleAuth/OnIntoBossRaid async void→async Task 전환 - await 후 스레드 안전성 확보 (sessionLock 도입) - 보스레이드 파티원 세션/토큰 개별 전달 (tokens Dictionary 타입 수정) - 409 Conflict 처리 추가, bossId 하드코딩 제거 - 채널 이동 시 레이드 맵 해제, 플레이어 상태 보존 - 파티원 닉네임 손실 수정, HandlePartyLeaveOnExit 알림 타입 수정 - PacketCode enum 명시적 값 할당, MaplId→MapId/BossRaidAccesss→Access 오타 수정 - Channel.UserCount 음수 방지, HandleAuth 재연결 로직 수정 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,9 @@ public abstract class ServerBase : INetEventListener
|
||||
// 재사용 NetDataWriter (단일 스레드 폴링이므로 안전)
|
||||
private readonly NetDataWriter cachedWriter = new();
|
||||
|
||||
// async 메서드(HandleAuth 등)의 await 이후 공유 자원 접근 보호용
|
||||
protected readonly object sessionLock = new();
|
||||
|
||||
// 핑 로그 출력 여부
|
||||
public bool PingLogRtt
|
||||
{
|
||||
@@ -118,26 +121,29 @@ public abstract class ServerBase : INetEventListener
|
||||
// 클라이언트가 연결 해제됐을 때 (타임아웃, 명시적 끊기 등)
|
||||
public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
|
||||
{
|
||||
pendingPeers.Remove(peer.Id);
|
||||
|
||||
if (peer.Tag is Session session)
|
||||
lock (sessionLock)
|
||||
{
|
||||
// 현재 인증된 피어가 이 peer일 때만 세션 제거
|
||||
// (재연결로 이미 교체된 경우엔 건드리지 않음)
|
||||
if (sessions.TryGetValue(session.HashKey, out NetPeer? current) && current.Id == peer.Id)
|
||||
pendingPeers.Remove(peer.Id);
|
||||
|
||||
if (peer.Tag is Session session)
|
||||
{
|
||||
// 더미 클라 아니면 token관리
|
||||
if (!string.IsNullOrEmpty(session.Token))
|
||||
// 현재 인증된 피어가 이 peer일 때만 세션 제거
|
||||
// (재연결로 이미 교체된 경우엔 건드리지 않음)
|
||||
if (sessions.TryGetValue(session.HashKey, out NetPeer? current) && current.Id == peer.Id)
|
||||
{
|
||||
tokenHash.Remove(session.Token);
|
||||
// 더미 클라 아니면 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);
|
||||
}
|
||||
|
||||
sessions.Remove(session.HashKey);
|
||||
Log.Information("[Server] 세션 해제 HashKey={Key} Reason={Reason}", session.HashKey, disconnectInfo.Reason);
|
||||
OnSessionDisconnected(peer, session.HashKey, disconnectInfo);
|
||||
peer.Tag = null;
|
||||
}
|
||||
|
||||
peer.Tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +173,11 @@ public abstract class ServerBase : INetEventListener
|
||||
// Auth 패킷은 베이스에서 처리 (raw 8-byte long, protobuf 불필요)
|
||||
if (type == (ushort)PacketType.ACC_TOKEN)
|
||||
{
|
||||
HandleAuth(peer, payload);
|
||||
_ = HandleAuth(peer, payload).ContinueWith(t =>
|
||||
{
|
||||
if (t.IsFaulted)
|
||||
Log.Error(t.Exception, "[Server] HandleAuth 예외 PeerId={Id}", peer.Id);
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
return;
|
||||
}
|
||||
else if (type == (ushort)PacketType.DUMMY_ACC_TOKEN)
|
||||
@@ -240,7 +250,7 @@ public abstract class ServerBase : INetEventListener
|
||||
|
||||
// ─── Auth 처리 ────────────────────────────────────────────────
|
||||
|
||||
protected abstract void HandleAuth(NetPeer peer, byte[] payload);
|
||||
protected abstract Task HandleAuth(NetPeer peer, byte[] payload);
|
||||
|
||||
// ─── 전송 헬퍼 ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user