43. 인증 완료 전 도착 패킷의 미인증 처리와 상태 게이트 부재
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] 인증 완료 전에 도착한 게임 패킷의 처리 순서 (핸드셰이크 경합)
// ----------------------------------------------------------------------------
// 시나리오:
// 클라이언트가 접속하면 서버는 먼저 AUTH 패킷의 토큰을 비동기로 검증한다(외부 인증 서버 호출).
// 검증이 끝나면 세션에 계정 식별자를 채우고 인증 완료 상태로 전이한다.
// 그런데 클라이언트는 접속 직후 인증 응답을 기다리지 않고 이동/명령 패킷을 곧바로 보낼 수 있다.
//
// 요구사항:
// - 인증이 끝나기 전 도착한 게임 명령은 인증된 신원으로만 처리되어야 한다
// (미인증 상태에서 실행되거나, 잘못된 신원으로 실행되면 안 된다).
// - 인증 완료 처리(신원 기록)와 이후 명령 처리 사이에 상태가 뒤섞이면 안 된다.
//
// 과제:
// SessionDispatcher.OnReceive 의 (A)(B) 를 검토하라. 클라가 접속 직후
// AUTH 와 MOVE 를 연달아 보내고, 인증 검증이 비동기로 진행되는 흐름을 따라가며
// 어떤 결과가 나올 수 있는지, 어떻게 고쳐야 하는지 설명하라.
// ============================================================================
using System.Threading.Tasks;
public enum SessionState { Connecting, Authenticating, Authenticated }
public sealed class Session
{
public long AccountId; // 인증 완료 후 채워짐 (기본 0)
public SessionState State = SessionState.Connecting;
}
public sealed class SessionDispatcher
{
private readonly IAuthService _auth;
private readonly ICommandHandler _handler;
public SessionDispatcher(IAuthService auth, ICommandHandler handler) { _auth = auth; _handler = handler; }
public void OnReceive(Session session, Packet msg)
{
switch (msg.Type)
{
case MsgType.Auth:
session.State = SessionState.Authenticating;
_auth.ValidateAsync(msg.Token).ContinueWith(t =>
{
session.AccountId = t.Result.AccountId;
session.State = SessionState.Authenticated; // (A)
});
break;
default:
_handler.Handle(session, msg); // (B)
break;
}
}
}
public enum MsgType { Auth, Move, UseItem, Chat }
public sealed class Packet { public MsgType Type; public string Token = ""; public byte[] Body = System.Array.Empty<byte>(); }
public sealed class AuthResult { public long AccountId; }
public interface IAuthService { Task<AuthResult> ValidateAsync(string token); }
public interface ICommandHandler { void Handle(Session session, Packet msg); } 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] 인증 완료 전 도착 패킷 처리와 비동기 인증 콜백의 세션 수명
// ----------------------------------------------------------------------------
// 시나리오:
// 접속 시 서버는 AUTH 패킷의 토큰을 비동기로 검증한다(외부 인증 서버). 검증 완료 콜백에서
// 세션에 계정 식별자를 채우고 인증 완료로 전이한다. 클라는 접속 직후 인증을 기다리지 않고
// 이동/명령 패킷을 곧바로 보낼 수 있고, 검증 대기 중 연결을 끊을 수도 있다.
//
// 요구사항:
// - 인증 전 도착한 게임 명령은 인증된 신원으로만 처리되어야 한다.
// - 인증 검증이 진행되는 동안 세션이 사라져도 안전해야 한다.
//
// 과제:
// SessionDispatcher::onReceive 의 (A)(B) 를 검토하라. 접속 직후 AUTH+MOVE 를 연달아 보내고,
// 검증이 끝나기 전에 연결이 종료되는 흐름을 따라가며 결과와 수정 방향을 설명하라.
// ============================================================================
#include <functional>
#include <vector>
#include <string>
#include <cstdint>
enum class SessionState { Connecting, Authenticating, Authenticated };
enum class MsgType { Auth, Move, UseItem, Chat };
struct Packet { MsgType type; std::string token; std::vector<uint8_t> body; };
struct AuthResult { int64_t accountId; bool ok; };
struct Session {
int64_t accountId = 0; // 인증 완료 후 채워짐
SessionState state = SessionState::Connecting;
};
// 비동기 인증: 결과가 나오면 콜백을 (다른 스레드에서) 호출한다.
struct IAuthService {
virtual void validateAsync(const std::string& token, std::function<void(AuthResult)> cb) = 0;
virtual ~IAuthService() = default;
};
struct ICommandHandler {
virtual void handle(Session& s, const Packet& msg) = 0;
virtual ~ICommandHandler() = default;
};
class SessionDispatcher {
public:
SessionDispatcher(IAuthService& auth, ICommandHandler& handler) : auth_(auth), handler_(handler) {}
void onReceive(Session* session, const Packet& msg) {
switch (msg.type) {
case MsgType::Auth:
session->state = SessionState::Authenticating;
auth_.validateAsync(msg.token, [session](AuthResult r) {
session->accountId = r.accountId;
session->state = SessionState::Authenticated; // (A)
});
break;
default:
handler_.handle(*session, msg); // (B)
break;
}
}
private:
IAuthService& auth_;
ICommandHandler& handler_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.