feat: 중복 로그인 방지 코드 추가
This commit is contained in:
parent
1d103d7f16
commit
17013f70f5
6 changed files with 102 additions and 7 deletions
|
|
@ -33,13 +33,38 @@ bool BaseClient::ReceiveHeader(PacketHeader &header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseClient::Login(const std::string &nickname) {
|
bool BaseClient::Login(const std::string &nickname) {
|
||||||
PKT_CS_Login loginPkt;
|
PKT_CS_Login loginPkt;
|
||||||
std::memset(loginPkt.nickname, 0, sizeof(loginPkt.nickname));
|
std::memset(loginPkt.nickname, 0, sizeof(loginPkt.nickname));
|
||||||
std::strncpy(loginPkt.nickname, nickname.c_str(),
|
std::strncpy(loginPkt.nickname, nickname.c_str(),
|
||||||
sizeof(loginPkt.nickname) - 1);
|
sizeof(loginPkt.nickname) - 1);
|
||||||
SendPacket(PacketID::Login, &loginPkt, sizeof(loginPkt));
|
SendPacket(PacketID::Login, &loginPkt, sizeof(loginPkt));
|
||||||
std::cout << "로그인 요청 보냄: " << nickname << std::endl;
|
std::cout << "로그인 요청 보냄: " << nickname << std::endl;
|
||||||
|
|
||||||
|
// 로그인 결과 대기
|
||||||
|
PacketHeader header;
|
||||||
|
if (!ReceiveHeader(header) ||
|
||||||
|
header.id != static_cast<uint16_t>(PacketID::SC_LoginResult)) {
|
||||||
|
std::cerr << "로그인 응답을 받지 못했습니다." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PKT_SC_LoginResult res;
|
||||||
|
if (!ReceivePayload(res)) {
|
||||||
|
std::cerr << "로그인 응답 수신 실패" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.result == 1) {
|
||||||
|
std::cout << "로그인 성공!" << std::endl;
|
||||||
|
return true;
|
||||||
|
} else if (res.result == 0) {
|
||||||
|
std::cerr << "로그인 실패: 이미 접속 중인 유저입니다." << std::endl;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
std::cerr << "로그인 실패: 알 수 없는 오류" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseClient::HandleUpgradeResult() {
|
void BaseClient::HandleUpgradeResult() {
|
||||||
|
|
@ -68,7 +93,10 @@ void BaseClient::HandleSellResult() {
|
||||||
void InteractiveClient::Run() {
|
void InteractiveClient::Run() {
|
||||||
std::cout << "닉네임을 입력하세요: ";
|
std::cout << "닉네임을 입력하세요: ";
|
||||||
std::cin >> nickname_;
|
std::cin >> nickname_;
|
||||||
Login(nickname_);
|
if (!Login(nickname_)) {
|
||||||
|
std::cerr << "로그인에 실패하여 종료합니다." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (currentLevel_ == 0) {
|
if (currentLevel_ == 0) {
|
||||||
|
|
@ -128,7 +156,10 @@ void ScenarioClient::Run() {
|
||||||
|
|
||||||
if (!(is >> nickname_))
|
if (!(is >> nickname_))
|
||||||
return;
|
return;
|
||||||
Login(nickname_);
|
if (!Login(nickname_)) {
|
||||||
|
std::cerr << "로그인에 실패하여 종료합니다." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
while (is >> line) {
|
while (is >> line) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Login(const std::string &nickname);
|
bool Login(const std::string &nickname);
|
||||||
|
|
||||||
virtual void Run() = 0;
|
virtual void Run() = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ enum class PacketID : uint16_t {
|
||||||
Ping = 1,
|
Ping = 1,
|
||||||
// 로그인 요청 (PKT_CS_Login)
|
// 로그인 요청 (PKT_CS_Login)
|
||||||
Login = 10,
|
Login = 10,
|
||||||
|
// 로그인 결과 응답 (PKT_SC_LoginResult)
|
||||||
|
SC_LoginResult = 11,
|
||||||
Chat = 20,
|
Chat = 20,
|
||||||
|
|
||||||
// 검 키우기 관련 패킷
|
// 검 키우기 관련 패킷
|
||||||
|
|
@ -52,6 +54,11 @@ struct PKT_CS_Login {
|
||||||
char nickname[32];
|
char nickname[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PKT_SC_LoginResult {
|
||||||
|
// 0: 이미 접속 중, 1: 성공
|
||||||
|
uint8_t result;
|
||||||
|
};
|
||||||
|
|
||||||
struct PKT_SC_UpgradeResult {
|
struct PKT_SC_UpgradeResult {
|
||||||
// 0: 파괴, 1: 성공, 2: 실패
|
// 0: 파괴, 1: 성공, 2: 실패
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ public:
|
||||||
static SessionManager &GetInstance();
|
static SessionManager &GetInstance();
|
||||||
|
|
||||||
void Join(std::shared_ptr<Session> session);
|
void Join(std::shared_ptr<Session> session);
|
||||||
|
bool TryJoin(std::shared_ptr<Session> session, const std::string &nickname);
|
||||||
void Leave(std::shared_ptr<Session> session);
|
void Leave(std::shared_ptr<Session> session);
|
||||||
void Broadcast(PacketHeader header, std::span<const uint8_t> body);
|
void Broadcast(PacketHeader header, std::span<const uint8_t> body);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,50 @@ PacketHandler::HandlePacket(std::shared_ptr<Session> session,
|
||||||
|
|
||||||
auto userData = co_await DatabaseManager::GetInstance().LoadUser(nickname);
|
auto userData = co_await DatabaseManager::GetInstance().LoadUser(nickname);
|
||||||
|
|
||||||
session->SetNickname(userData.nickname);
|
// 골드와 검 레벨 설정 (닉네임은 TryJoin에서 설정)
|
||||||
session->SetGold(userData.gold);
|
session->SetGold(userData.gold);
|
||||||
session->SetSwordLevel(userData.swordLevel);
|
session->SetSwordLevel(userData.swordLevel);
|
||||||
|
|
||||||
Logger::Log("클라이언트 로그인: ", nickname, " (Gold: ", session->GetGold(),
|
PKT_SC_LoginResult loginResult;
|
||||||
|
|
||||||
|
// 원자적으로 중복 체크 및 세션 추가
|
||||||
|
if (!SessionManager::GetInstance().TryJoin(session, userData.nickname)) {
|
||||||
|
// 이미 접속 중인 유저
|
||||||
|
Logger::Log("중복 로그인 거부: ", nickname);
|
||||||
|
loginResult.result = 0;
|
||||||
|
|
||||||
|
PacketHeader header;
|
||||||
|
header.id = static_cast<uint16_t>(PacketID::SC_LoginResult);
|
||||||
|
header.size = sizeof(PKT_SC_LoginResult);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer(sizeof(PacketHeader) +
|
||||||
|
sizeof(PKT_SC_LoginResult));
|
||||||
|
std::memcpy(buffer.data(), &header, sizeof(PacketHeader));
|
||||||
|
std::memcpy(buffer.data() + sizeof(PacketHeader), &loginResult,
|
||||||
|
sizeof(PKT_SC_LoginResult));
|
||||||
|
|
||||||
|
session->Send(buffer);
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Log("클라이언트 로그인 성공: ", nickname,
|
||||||
|
" (Gold: ", session->GetGold(),
|
||||||
", Level: ", session->GetSwordLevel(), ")");
|
", Level: ", session->GetSwordLevel(), ")");
|
||||||
|
|
||||||
SessionManager::GetInstance().Join(session);
|
// 로그인 성공 응답
|
||||||
|
loginResult.result = 1;
|
||||||
|
|
||||||
|
PacketHeader header;
|
||||||
|
header.id = static_cast<uint16_t>(PacketID::SC_LoginResult);
|
||||||
|
header.size = sizeof(PKT_SC_LoginResult);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer(sizeof(PacketHeader) +
|
||||||
|
sizeof(PKT_SC_LoginResult));
|
||||||
|
std::memcpy(buffer.data(), &header, sizeof(PacketHeader));
|
||||||
|
std::memcpy(buffer.data() + sizeof(PacketHeader), &loginResult,
|
||||||
|
sizeof(PKT_SC_LoginResult));
|
||||||
|
|
||||||
|
session->Send(buffer);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case PacketID::CS_UpgradeSword: {
|
case PacketID::CS_UpgradeSword: {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,26 @@ void SessionManager::Leave(std::shared_ptr<Session> session) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SessionManager::TryJoin(std::shared_ptr<Session> session,
|
||||||
|
const std::string &nickname) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
// 중복 체크
|
||||||
|
for (const auto &existing : sessions_) {
|
||||||
|
if (existing->GetNickname() == nickname) {
|
||||||
|
Logger::Log("이미 접속 중인 유저 로그인 시도: ", nickname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 중복이 없으면 닉네임 설정 후 추가
|
||||||
|
session->SetNickname(nickname);
|
||||||
|
sessions_.insert(session);
|
||||||
|
Logger::Log("클라이언트[", nickname,
|
||||||
|
"]가 입장했습니다. 총 세션 수: ", sessions_.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SessionManager::Broadcast(PacketHeader header,
|
void SessionManager::Broadcast(PacketHeader header,
|
||||||
std::span<const uint8_t> body) {
|
std::span<const uint8_t> body) {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue