PacketHandler의 목적

  1. 서버와 클라이언트 간 통신에서 주고받는 데이터 패킷을 정형화된 형태로 처리.
  2. 패킷 ID 기반의 분기 처리를 통해 다양한 패킷을 구분하고 적절한 핸들링 함수를 호출.
  3. 가변 데이터(예: 리스트, 문자열)를 패킷에 포함하고 파싱하는 방법을 제공.
  4. 재사용 가능한 코드: 각 패킷을 정형화된 방식으로 구현하여 확장 및 유지보수가 쉽도록 함.

ServerPacketHandler 분석

ServerPacketHandler.h

#pragma once

enum
{
    S_TEST = 1  // 패킷 ID: 1 (서버 -> 클라이언트 테스트 패킷)
};

struct BuffData
{
    uint64 buffId;    // 버프의 ID
    float remainTime; // 남은 시간
};

class ServerPacketHandler
{
public:
    static void HandlePacket(BYTE* buffer, int32 len);

    static SendBufferRef Make_S_TEST(uint64 id, uint32 hp, uint16 attack, vector<BuffData> buffs);
};

상세 설명

  1. enum

    • 패킷 구분을 위한 ID 정의.
    • S_TEST = 1은 테스트 패킷 ID입니다.
  2. BuffData 구조체

    • 버프 데이터를 담는 구조체.
    • buffId: 버프의 고유 ID.
    • remainTime: 버프의 남은 시간.
  3. HandlePacket 함수

    • 패킷을 받아서 처리하는 핸들러 진입점.
  4. Make_S_TEST 함수

    • S_TEST 패킷을 만드는 함수.
    • 데이터를 버퍼에 쓰기(Serialize)해서 SendBuffer를 반환.

ServerPacketHandler.cpp

void ServerPacketHandler::HandlePacket(BYTE* buffer, int32 len)
{
    BufferReader br(buffer, len); // 버퍼를 읽기 위한 BufferReader 생성

    PacketHeader header;
    br.Peek(&header); // 헤더만 읽음 (커서는 이동하지 않음)

    switch (header.id)
    {
    default:
        break; // 정의된 패킷 ID가 아니면 무시
    }
}

핵심 설명: HandlePacket

  1. BufferReader: 버퍼 데이터를 읽는 헬퍼 클래스.
  2. PacketHeader
    • 패킷의 idsize를 포함한 구조체입니다.
    • br.Peek(&header): 헤더를 읽되 커서는 이동하지 않음.
  3. switch-case: 패킷 ID에 따라 분기.
    • 여기서는 default 처리만 있고, 이후 다양한 패킷을 추가하면 여기에 분기 처리를 추가할 수 있음.

SendBufferRef ServerPacketHandler::Make_S_TEST(uint64 id, uint32 hp, uint16 attack, vector<BuffData> buffs)
{
    SendBufferRef sendBuffer = make_shared<SendBuffer>(4096); // 4KB 버퍼 생성

    BufferWriter bw(sendBuffer->Buffer(), sendBuffer->Capacity()); // 버퍼에 데이터를 쓰기 위한 BufferWriter

    PacketHeader* header = bw.Reserve<PacketHeader>(); // 헤더를 위한 공간 확보
    bw << id << hp << attack; // id(uint64), 체력(uint32), 공격력(uint16)

    // 가변 데이터
    bw << (uint16)buffs.size(); // 버프 개수 저장
    for (BuffData& buff : buffs)
    {
        bw << buff.buffId << buff.remainTime; // 각 버프 데이터를 저장
    }

    header->size = bw.WriteSize(); // 패킷 전체 크기 설정
    header->id = S_TEST;           // 패킷 ID 설정

    sendBuffer->Close(bw.WriteSize()); // 버퍼 사이즈 지정

    return sendBuffer;
}

핵심 설명: Make_S_TEST

  1. SendBuffer

    • 전송을 위한 버퍼를 생성.
    • 4096 바이트(4KB)로 초기화.
  2. BufferWriter

    • 데이터를 버퍼에 쓰기 위한 헬퍼 클래스.
  3. Reserve

    • Reserve<PacketHeader>: 패킷 헤더 공간을 미리 확보합니다.
  4. Serialize

    • 패킷에 필요한 데이터를 순서대로 쓰기.
    • 고정 데이터: id, hp, attack은 primitive 타입이므로 바로 씀.
    • 가변 데이터:
      • 먼저 벡터의 크기를 저장 (buffs.size()).
      • 이후 벡터 순회하며 각 buffIdremainTime을 씀.
  5. 헤더 설정

    • header->size: 전체 패킷 크기.
    • header->id: 패킷 ID (S_TEST).
  6. 버퍼 닫기

    • sendBuffer->Close: 버퍼의 쓰기 크기를 확정.

ClientPacketHandler 분석

ClientPacketHandler.h

#pragma once

enum
{
    S_TEST = 1
};

class ClientPacketHandler
{
public:
    static void HandlePacket(BYTE* buffer, int32 len);

    static void Handle_S_TEST(BYTE* buffer, int32 len);
};

핵심 설명

  • 서버에서 보낸 패킷을 처리하는 핸들러입니다.
  • HandlePacket에서 패킷 ID를 확인하고 Handle_S_TEST 등 적절한 함수를 호출합니다.

ClientPacketHandler.cpp

void ClientPacketHandler::HandlePacket(BYTE* buffer, int32 len)
{
    BufferReader br(buffer, len); // 버퍼를 읽기 위한 BufferReader 생성

    PacketHeader header;
    br >> header; // 헤더를 읽음 (커서 이동)

    switch (header.id)
    {
    case S_TEST:
        Handle_S_TEST(buffer, len); // S_TEST 패킷 처리
        break;
    }
}
  1. 헤더 읽기: br >> header를 통해 헤더 데이터를 읽음.
  2. switch-case
    • 패킷 ID에 따라 적절한 핸들러 호출.
    • S_TEST ID면 Handle_S_TEST 호출.

void ClientPacketHandler::Handle_S_TEST(BYTE* buffer, int32 len)
{
    BufferReader br(buffer, len);

    PacketHeader header;
    br >> header;

    uint64 id;
    uint32 hp;
    uint16 attack;
    br >> id >> hp >> attack;

    cout << "ID: " << id << " HP : " << hp << " ATT : " << attack << endl;

    vector<BuffData> buffs;
    uint16 buffCount;
    br >> buffCount; // 버프 개수 읽기

    buffs.resize(buffCount);
    for (int32 i = 0; i < buffCount; i++)
    {
        br >> buffs[i].buffId >> buffs[i].remainTime; // 버프 데이터 읽기
    }

    cout << "BufCount : " << buffCount << endl;
    for (int32 i = 0; i < buffCount; i++)
    {
        cout << "BufInfo : " << buffs[i].buffId << " " << buffs[i].remainTime << endl;
    }
}

핵심 설명: Handle_S_TEST

  1. 헤더 읽기: br >> header.
  2. 고정 데이터 읽기: id, hp, attack.
  3. 가변 데이터 읽기
    • buffCount를 읽어 버프 개수를 확인.
    • buffs.resize(buffCount)로 벡터 크기 조정.
    • 반복문을 통해 각 buffIdremainTime을 읽어 벡터에 저장.
  4. 출력
    • 읽은 데이터를 콘솔에 출력.

PacketHandler의 활용

  1. 확장성

    • 새로운 패킷을 추가하려면 enum에 ID를 추가하고, 해당 패킷의 핸들러를 구현하면 됨.
  2. 가변 데이터 지원

    • 벡터, 문자열 등 가변 데이터를 다룰 수 있음.
  3. 정형화된 구조

    • BufferReaderBufferWriter를 통해 데이터 읽기/쓰기가 일관되게 처리됨.
    • 버퍼에 데이터를 SerializeDeserialize.

profile
李家네_공부방

0개의 댓글