35. 멀티 디바이스 세션 목록의 교체·제거 경합 (C#)
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 멀티 디바이스 동시 접속 세션 관리 (C#)
//
// 이 게임은 한 계정으로 여러 기기(PC·모바일)에서 동시에 접속할 수 있고,
// 같은 종류(플랫폼)에서는 1개만 허용한다. 즉 계정당 세션 목록을 유지하며,
// 같은 플랫폼의 새 로그인이 오면 그 플랫폼의 기존 세션만 킥한다.
//
// 요구사항:
// - 계정별 활성 세션 목록에 (플랫폼당 최대 1개) 세션을 등록한다.
// - 같은 플랫폼 재로그인 시 그 플랫폼의 기존 세션만 종료하고 새 세션으로 교체한다.
// - 로그아웃/연결 종료 시, "지금 그 연결에 해당하는" 세션만 목록에서 제거한다.
// - 로그인/로그아웃/재접속이 여러 스레드에서 동시에 일어날 수 있다.
//
// 아래 매니저를 검토하라. 표시된 지점 (A)(B)(C).
using System;
using System.Collections.Generic;
public sealed class Session
{
public long AccountId;
public string Platform = ""; // "pc" | "mobile"
public Guid ConnId = Guid.NewGuid();
public void Kick() { /* 소켓 종료 통지 */ }
}
public sealed class MultiSessionManager
{
// accountId -> (platform -> session)
private readonly Dictionary<long, Dictionary<string, Session>> _byAccount = new();
public void OnLogin(Session s)
{
if (!_byAccount.TryGetValue(s.AccountId, out var perPlatform))
{
perPlatform = new Dictionary<string, Session>();
_byAccount[s.AccountId] = perPlatform;
}
// (A) 같은 플랫폼 기존 세션 킥 후 교체
if (perPlatform.TryGetValue(s.Platform, out var old))
old.Kick();
perPlatform[s.Platform] = s; // (B) 새 세션 등록
}
public void OnDisconnect(Session s)
{
if (_byAccount.TryGetValue(s.AccountId, out var perPlatform))
{
// (C) 이 플랫폼 슬롯 제거
perPlatform.Remove(s.Platform);
if (perPlatform.Count == 0)
_byAccount.Remove(s.AccountId);
}
}
} 결함 코드 · C++
// 시나리오: 멀티 디바이스 동시 접속 세션 관리 (C++)
//
// 한 계정으로 여러 기기(PC·모바일)에서 동시에 접속할 수 있고, 같은 플랫폼에서는 1개만 허용한다.
// 계정당 세션 목록을 유지하며, 같은 플랫폼 재로그인 시 그 플랫폼의 기존 세션만 킥·교체한다.
//
// 요구사항:
// - 계정별 활성 세션 목록(플랫폼당 최대 1개)을 유지한다.
// - 로그아웃/연결 종료 시 "지금 그 연결에 해당하는" 세션만 목록에서 제거한다.
// - 로그인/로그아웃/재접속이 여러 스레드에서 동시에 일어날 수 있다.
//
// 세션은 shared_ptr 로 관리되고, 연결 계층은 자신이 들고 있는 세션 포인터로 OnDisconnect 를 부른다.
// 아래 매니저를 검토하라. 표시된 지점 (A)(B)(C).
#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
struct Session {
std::int64_t accountId;
std::string platform; // "pc" | "mobile"
std::uint64_t connId; // 연결마다 고유
void Kick() { /* 소켓 종료 통지 */ }
};
class MultiSessionManager {
public:
void OnLogin(std::shared_ptr<Session> s) {
auto& perPlatform = byAccount_[s->accountId];
// (A) 같은 플랫폼 기존 세션 킥
auto it = perPlatform.find(s->platform);
if (it != perPlatform.end())
it->second->Kick();
perPlatform[s->platform] = s; // (B) 새 세션 등록
}
void OnDisconnect(std::shared_ptr<Session> s) {
auto ait = byAccount_.find(s->accountId);
if (ait == byAccount_.end()) return;
auto& perPlatform = ait->second;
// (C) 이 플랫폼 슬롯 제거
perPlatform.erase(s->platform);
if (perPlatform.empty())
byAccount_.erase(ait);
}
private:
std::unordered_map<std::int64_t,
std::unordered_map<std::string, std::shared_ptr<Session>>> byAccount_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.