저번엔 DummyClient를 동작 가능한 상태까지 만들고, 인증서버로 메시지를 보내서 인증서버가 잘 읽는지까지 확인해봤다.
이번엔 클라이언트로부터 메시지를 받은 인증서버가 response 패킷을 만들어서 보내고, 또 클라이언트에서 거기에 response하도록 만들어보자. 아직 실제로 DB를 사용하진 않고, db 사용할 부분을 sleep으로 떼워넣자.

대략적으로 클라, 인증서버, DB가 위와같은 형태로 통신할것이다.
지난번에 만든 더미클라이언트를 사용해서 클라 -> 서버, 서버 -> 클라가 자동적으로 잘 이루어지는지 확인해볼 차례다.
이것을 위해서 인증서버의 ClientPacketHandler.cpp, 더미클라의 ServerPacketHander.cpp 에서의 각 패킷 Handler함수를 적절하게 만들어봤다. 별 대단한건 없고 그냥 패킷을 받으면 다음에 줘야할 패킷을 만든 뒤에 패킷을 WriteBuffer로 만들어서 Session의 Send합수를 사용해 보낸다.
ClientPacketHandler.cpp
void Handle_C_SIGNUP(PacketSessionRef session, const Protocol::C_SIGNUP& pkt)
{
std::string email, nickname, password;
email = pkt.email();
nickname = pkt.nickname();
password = pkt.password();
/* TODO DB에서 email, nickname 이미 있는지 확인.
중복 있으면 실패, disconnect(해야할까?). 없으면 다음 단계로.
*/
std::this_thread::sleep_for(std::chrono::milliseconds(100));//DB작업(0.1초 걸렸다 침)
Protocol::S_SIGNUP response;
if (true)
{
response.set_success(true);
//중복 없으면 성공했다고 알림. 이메일인증쪽은 고민좀 해보자.
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_SIGNUP));
}
else
{
response.set_success(false);
//중복있으면 실패했다고 알림
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_SIGNUP));
}
}
void Handle_C_VERIFY_EMAIL(PacketSessionRef session, const Protocol::C_VERIFY_EMAIL& pkt)
{
std::string email = pkt.email();
std::string code = pkt.verification_code();
// 서버에서 준 코드와 클라이언트가 보낸 코드가 일치하는지 확인
std::this_thread::sleep_for(std::chrono::milliseconds(100));//DB작업(0.1초 걸렸다 침)
Protocol::S_VERIFY_EMAIL response;
if (code == code)
{
//코드 일치하면 postgres에 새 계정 정보 INSERT 시도.
//INSERT 성공 시 성공 패킷 보냄. 실패 시 실패 패킷 보냄.
response.set_success(true);
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_VERIFY_EMAIL));
}
else
{
//코드 일치하지 않으면 실패 패킷 보냄
response.set_success(false);
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_VERIFY_EMAIL));
//disconnect?
}
}
void Handle_C_LOGIN(PacketSessionRef session, const Protocol::C_LOGIN& pkt)
{
std::string nickname = pkt.nickname();
std::string password = pkt.password();
//password 해싱해서 postgres에 있는 해싱된 password와 일치하는지 확인.
//일치하면 클라이언트에게 로그인토큰 발급해줌, redis에 로그인토큰 저장
std::this_thread::sleep_for(std::chrono::milliseconds(100));//DB작업(0.1초 걸렸다 침)
Protocol::S_LOGIN response;
if (true)
{
response.set_success(true);
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_LOGIN));
}
else
{
response.set_success(false);
session->Send(ClientPacketHandler::MakeWriteBuffer(response, PKT_S_LOGIN));
session->Disconnect();
}
}
ServerPacketHander.cpp
#include "ServerPacketHandler.h"
#include <thread>
std::function<bool(std::function<void()>&, PacketSessionRef, BYTE*, int32)> GPacketHandler[UINT16_MAX];
bool Handle_INVALID(std::function<void()>& outFunc, PacketSessionRef session, BYTE* buffer, int32 len)
{
return false;
}
void Handle_S_SIGNUP(PacketSessionRef session, Protocol::S_SIGNUP pkt)
{
bool success = pkt.success();
if (success == true)
{//만들 수 있는 계정이면 이메일 인증 창 띄우기.
Protocol::C_VERIFY_EMAIL response;
response.set_email("email");//이메일
response.set_verification_code("332134");//인증코드
std::cout << session->GetFd() << " : you can use nickname/email \n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));//DB작업(0.1초 걸렸다 침)
session->Send(ServerPacketHandler::MakeWriteBuffer(response, PKT_C_VERIFY_EMAIL));
}
else
{//이미 있는 nickname / email입니다. 문구띄우기
std::cout << session->GetFd() << " : nickname aleady used\n";
session->Disconnect();
}
}
void Handle_S_VERIFY_EMAIL(PacketSessionRef session, Protocol::S_VERIFY_EMAIL pkt)
{
bool success = pkt.success();
Protocol::C_LOGIN response;
if (success == true)
{//이메일 인증 성공 시
std::cout << session->GetFd() << " : Verification Success!\n";
response.set_nickname("Dodontak");
response.set_password("password123");
session->Send(ServerPacketHandler::MakeWriteBuffer(response, PKT_C_LOGIN));
}
else
{//실패 시 재도전 가능?
std::cout << session->GetFd() << "wrong verification code!\n";
session->Disconnect();
}
}
void Handle_S_LOGIN(PacketSessionRef session, Protocol::S_LOGIN pkt)
{
bool success = pkt.success();
if (success == true)
std::cout << session->GetFd() << " : login Success!\n";
else
std::cout << session->GetFd() << " : login Failed!\n";
}
void Broadcast(ClientServiceRef service)
{
Protocol::C_SIGNUP pkt;
pkt.set_email("asd@naver.com");
pkt.set_nickname("Dodontak");
pkt.set_password("password123");
WriteBufferRef writeBuffer = ServerPacketHandler::MakeWriteBuffer(pkt, PKT_C_SIGNUP);
service->broadcastfortest(writeBuffer);
}
테스트로 서버에 접속한 모든 클라이언트가 회원가입 패킷을 서버에 전송하는 상황을 만들어봤다. 클라이언트는 10명으로 설정했다.

성공적으로 잘 되는 모습이다.
이제 인증서버에서 더 구현해야하는 부분이 뭔지 정리해보자.
- RedisConnectionPool
Redis를 활용한 세션토큰 발급과 활용방법공부 필요. - SQL쿼리 바인더
현재는 sql인젝션에 취약한 상태임 - 비밀번호 해싱과 관리
- 타이머 관리
타이머를 만들긴 했는데 사용이 불편하고, 적절한 해제방법은 구현하지 않았음 - 이메일 API 사용
- Client/Server PacketHandler.h 코드 자동생성 기능 만들기
게임서버강의에서 배운 Protocol.proto 파일을 파싱해서 패킷핸들러 헤더를 자동으로 만들어주는 프로그램을 만들자.
이정도만 하면 슬슬 인증서버도 마무리될 것 같다. 여기에 추가로 지저분한 코드들 정리, 리팩토링 하는정도로.
지금이 3월7일 밤인데, 3월 10일까지 인증서버는 마무리할 수 있도록 해보자. 그때쯤 되면 윈도우pc 고장난 부품 as보낸것도 슬슬 돌아올 것 같으니 IOCP 게임서버를 처음부터 다시 만들어보면서 배웠던 것들을 다시 익히고, 동시에 언리얼 클라이언트 작업도 진행해보자.
'프로젝트 > Project_Island' 카테고리의 다른 글
| 15. 패킷 자동화 (2) (0) | 2026.03.08 |
|---|---|
| 14. 패킷 자동화 (1) (0) | 2026.03.08 |
| 12. DummyClient (2) (0) | 2026.03.06 |
| 11. DummyClient (1) (0) | 2026.03.06 |
| 10. 프로젝트 리펙토링 + 모듈화 (0) | 2026.03.06 |