저번엔 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명으로 설정했다.

더미클라이언트 stdout

성공적으로 잘 되는 모습이다.


이제 인증서버에서 더 구현해야하는 부분이 뭔지 정리해보자.

  • 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

+ Recent posts