지난번에는 패킷핸들러를 추가하고, 코드생성 자동화를 했다. 그리고 컴파일이 되는지만 확인해봤다.
생성된 코드를 사용해서 기존의 채팅서버를 한번 굴려보도록 하자.
더미클라이언트에서 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 |