지난번에는 패킷핸들러를 추가하고, 코드생성 자동화를 했다. 그리고 컴파일이 되는지만 확인해봤다.

생성된 코드를 사용해서 기존의 채팅서버를 한번 굴려보도록 하자.


더미클라이언트에서 Send 하는 부분 변경

패킷 핸들러 Init을 반드시 해줘야한다.

/*...*/
#include "ServerPacketHandler.h"

int main()
{
	cout << "=== DummyClient ===" << endl;
    ServerPacketHandler::Init();
	/*...*/
	while (true)
	{
		this_thread::sleep_for(chrono::seconds(1));
        //string msg = "Hello Iocp Server!";
        //service->broad_cast_test(Utils::MakeChatSendBuffer(0, (BYTE*)msg.data(), msg.length()));
		Protocol::C_CHAT pkt;
		pkt.set_user_id(1);
		pkt.set_msg("Hello Iocp Server!");
		service->broad_cast_test(ServerPacketHandler::MakeSendBuffer(pkt));
	}
}

 

게임서버 main에서도 Init 추가.

/*...*/
#include "ClientPacketHandler.h"

int main()
{
	cout << "=== GameServer ===" << endl;
	ClientPacketHandler::Init();
	/*...*/
}

 

게임서버에서 단위패킷 실행시키는 부분 수정

#include "ClientPacketHandler.h"

void GameSession::OnRecvPacket(BYTE* buffer, uint32 size)
{
	function<void()> func;
	ClientPacketHandler::PacketHandler(func, static_pointer_cast<PacketSession>(shared_from_this()),
		buffer, size);
	func();
	//uint16 headerSize = sizeof(PacketHeader);
	//SendBufferRef sendBuffer = Utils::MakeChatSendBuffer(1, buffer + headerSize, size - headerSize);
	//if (ServiceRef service = _service.lock())
	//{
	//	service->broad_cast_test(sendBuffer);
	//}
}

// 새 함수 BroadCast 추가
void GameSession::BroadCast(SendBufferRef sendBuffer)
{
	if (ServiceRef service = _service.lock())
	{
		service->broad_cast_test(sendBuffer);
	}
}

여기서 func에는 Handle_C_CHAT 함수와 사용될 인자들이 담기는데, 원래는 job queue에 넣으면서 cv.notify_one() 으로 자고있던 스레드를 깨워 실행하게 만들었지만, 아직 게임서버에는 JobQueue를 만들지 않았기 때문에 그냥 즉시 실행하자.

 

Handle_C_CHAT 수정

ClientPacketHandler.cpp 에 있음

void	Handle_C_CHAT(const PacketSessionRef& session, const Protocol::C_CHAT& pkt)
{
	Protocol::S_CHAT response;
	GameSessionRef gameSession = static_pointer_cast<GameSession>(session);

	response.set_msg(pkt.msg());
	gameSession->BroadCast(ClientPacketHandler::MakeSendBuffer(response));
}

S_CHAT 패킷을 만들어 gameSession.BroadCast를 호출한다.

 

response를 받은 더미 클라이언트 측의 처리

void ServerSession::OnRecvPacket(BYTE* buffer, uint32 size)
{
	function<void()> func;
	ServerPacketHandler::PacketHandler(func, static_pointer_cast<PacketSession>(shared_from_this()),
		buffer, size);
	func();
	//uint16 headerSize = sizeof(PacketHeader);
	//string str((char*)(buffer + headerSize), size - headerSize);
	//Utils::LockPrint("recv from server : ", str);
}

 

Handle_S_CHAT 수정

ServerPacketHandler.cpp에 있음

void	Handle_S_CHAT(const PacketSessionRef& session, const Protocol::S_CHAT& pkt)
{
	Utils::LockPrint("recv from server : ", pkt.msg());
}

서버로 부터 온 메시지를 그냥 출력한다.

 

그리고 예전에 Session::Send에서 더미클라이언트에서만 뭘 send했는지 출력하는 코드 있었는데 제거해주자. (저번에 했어야했는데 안했다.)

void	 Session::Send(SendBufferRef sendBuffer)
{
	{
		lock_guard<mutex> lock(_m);
		_sendBuffers.push(sendBuffer);
	}
//제거
	//if (dynamic_pointer_cast<ClientService>(_service.lock()))
	//{//더미 클라이언트 서비스라면.
	//	string str((char*)sendBuffer->GetBuffer(), sendBuffer->GetDataLen());
	//	Utils::LockPrint("send : ", str);
	//}

	bool expected = false;
	if (_sendRegistered.compare_exchange_strong(expected, true))
	{
		RegisterSend();
	}
}

클라이언트 3개가 1초마다 서버로 Helli Iocp Server! 가 담긴 C_CHAT 패킷을 보내고

서버는 그걸 받아서 S_CHAT 패킷에 담아서 모든 클라이언트에게 보내준다.

클라이언트는 S_CHAT 패킷을 받으면 받은 내용을 출력한다.

 

잘 된다!


지금까지의 git 버전

 

Refactor: 기존 채팅서버 코드를 패킷핸들러 코드로 교체 · Dodontak/Project_Island_GameServer@9cb7b9e

GameServer - main에 ClientPacketHandler::init 추가 GameSession - 클라로부터 받은 메시지 브로드캐스트 하는 부분 패킷핸들러 사용하는 형태로 변경 - broad_cast_test 함수 추가 패킷핸들러에서 테스트 할 수 있

github.com

이제 protobuf를 사용한 패킷 송수신까지 만들었으니 본격적으로 게임에 어떤 컨텐츠를 넣을지, 어떤 패킷 송수신이 필요할지, 이동 동기화는 어떻게 할지 고민해볼 차례다. 게임서버 강의를 들으면서 느낀건데, 처음에 패킷 구조를 잘 잡아놓아야 나중에 패킷 바꾸면서 리팩터링 하는 고생을 줄일 수 있으니 처음에 잘 구성해놔야 한다.

'프로젝트 > Project_Island' 카테고리의 다른 글

39. DBConnection, Pool 만들기  (0) 2026.04.09
38. TLS 적용하기  (0) 2026.04.05
36. PacketHandler추가, 코드 자동화  (0) 2026.04.03
35. Protobuf 추가하기  (0) 2026.04.02
34. PacketHeader, PacketSession 추가  (0) 2026.04.02

+ Recent posts