상세 컨텐츠

본문 제목

Buffer Helpers

똑똑한 개발/C++ 게임개발

by 성댕쓰 2023. 4. 19. 22:38

본문

버퍼에 데이터 쓰고 읽는데 도움주는 클래스를 만들어 보자.

BufferReader.h, BufferReader.cpp

#pragma once

/*--------------------
	BufferReader
--------------------*/

class BufferReader
{
public:
	BufferReader();
	BufferReader(BYTE* buffer, uint32 size, uint32 pos = 0);
	~BufferReader();

	BYTE* Buffer() { return _buffer; }
	uint32 Size() { return _size; }
	uint32 ReadSize() { return _pos; }
	uint32 FreeSize() { return _size - _pos; }

	template<typename T>
	bool Peek(T* dest) { return Peek(dest, sizeof(T)); }
	bool Peek(void* dest, uint32 len);

	template<typename T>
	bool Read(T* dest) { return Read(dest, sizeof(T)); }
	bool Read(void* dest, uint32 len);

	template<typename T>
	BufferReader& operator>>(OUT T& dest);

private:
	BYTE* _buffer = nullptr;
	uint32 _size = 0;
	uint32 _pos = 0;

};

template<typename T>
BufferReader& BufferReader::operator>>(OUT T& dest)
{
	dest = *reinterpret_cast<T*>(&_buffer[_pos]);
	_pos += sizeof(T);
	return *this;
}
#include "pch.h"
#include "BufferReader.h"

/*--------------------
	BufferReader
--------------------*/

BufferReader::BufferReader()
{
}

BufferReader::BufferReader(BYTE* buffer, uint32 size, uint32 pos /*=0*/)
	:_buffer(buffer), _size(size), _pos(pos)
{
}

BufferReader::~BufferReader()
{
}

bool BufferReader::Peek(void* dest, uint32 len)
{
	if (FreeSize() < len)
		return false;

	::memcpy(dest, &_buffer[_pos], len);
	return true;
}

bool BufferReader::Read(void* dest, uint32 len)
{
	if (Peek(dest, len) == false)
		return false;

	_pos += len;
	return true;
}

 

BufferWriter.h, BufferWriter.cpp

#pragma once
/*--------------------
	BufferWriter
--------------------*/

class BufferWriter
{
public:
	BufferWriter();
	BufferWriter(BYTE* buffer, uint32 size, uint32 pos = 0);
	~BufferWriter();

	BYTE* Buffer() { return _buffer; }
	uint32 Size() { return _size; }
	uint32 WriteSize() { return _pos; }
	uint32 FreeSize() { return _size - _pos; }

	template<typename T>
	bool Write(T* src) { return Write(src, sizeof(T)); }
	bool Write(void* src, uint32 len);

	template<typename T>
	T* Reserve();

	template<typename T>
	BufferWriter& operator<<(const T& src);

	template<typename T>
	BufferWriter& operator<<(T&& src);

private:
	BYTE* _buffer = nullptr;
	uint32 _size = 0;
	uint32 _pos = 0;

};

template<typename T>
T* BufferWriter::Reserve()
{
	if (FreeSize() < sizeof(T))
		return nullptr;

	T* ret = reinterpret_cast<T*>(&_buffer[_pos]);
	_pos += sizeof(T);
	return ret;
}

template<typename T>
BufferWriter& BufferWriter::operator<<(const T& src)
{
	*reinterpret_cast<T*>(&_buffer[_pos]) = src;
	_pos += sizeof(T);
	return *this;
}

template<typename T>
BufferWriter& BufferWriter::operator<<(T&& src)
{
	*reinterpret_cast<T*>(&_buffer[_pos]) = std::move(src);
	_pos += sizeof(T);
	return *this;
}
#include "pch.h"
#include "BufferWriter.h"

/*--------------------
	BufferWriter
--------------------*/

BufferWriter::BufferWriter()
{
}

BufferWriter::BufferWriter(BYTE* buffer, uint32 size, uint32 pos)
	:_buffer(buffer), _size(size), _pos(pos)
{
}

BufferWriter::~BufferWriter()
{
}

bool BufferWriter::Write(void* src, uint32 len)
{
	if (FreeSize() < len)
		return false;

	::memcpy(&_buffer[_pos], src, len);
	_pos += len;
	return true;
}

BufferWriter는 아래처럼 사용

GameServer.cpp

...
while (true)
{
    SendBufferRef sendBuffer = GSendBufferManager->Open(4096);
    
    BufferWriter bw(sendBuffer->Buffer(), 4096);

    PacketHeader* header = bw.Reserve<PacketHeader>();
    // id(uint64), 체력(uint32), 공격력(uint16)
    bw << (uint64)1001 << (uint32)100 << (uint16)10;
    bw.Write(sendData, sizeof(sendData));

    header->size = bw.WriteSize();
    header->id = 1; // 1 : Test Msg

    sendBuffer->Close(bw.WriteSize());
    
    GSessionManager.Broadcast(sendBuffer);

    this_thread::sleep_for(250ms);
}
...

BufferReader는 아래처럼 사용

DummyClient.cpp

...
virtual int32 OnRecvPacket(BYTE* buffer, int32 len) override
{
    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;

    char recvBuffer[4096];
    br.Read(recvBuffer, header.size - sizeof(PacketHeader) - 8 - 4 - 2);
    cout << recvBuffer << endl;

    return len;
}
...

 

1. BufferReader operator >> 이 하는 역할은?

- 데이터를 읽고 position을 읽은 만큼 이동시킴.

 

2. Peek 의 역할은?

- 데이터를 파싱할 수 있는지 확인함.

 

3. BufferReader 사용법과 설명, BufferWriter 사용법과 설명?

- BufferReader : Iocp Recv 이벤트 받음> ProcessRecv >  OnRecv > OnRecvPacket 에서 write한 순서대로 읽음 마지막 len 계산은 가변길이 정보 읽는 방법 보여준 것.

- BufferWriter : SendBufferRef 생성 > BufferWriter 생성 > '<<' operator로 write > 'Hello World' 가변길이 데이터 보내기

 

'똑똑한 개발 > C++ 게임개발' 카테고리의 다른 글

Unicode  (0) 2023.05.07
PacketHandler  (0) 2023.05.06
Packet Session  (0) 2023.04.16
SendBuffer Pooling  (0) 2023.04.05
SendBuffer  (0) 2021.12.21

관련글 더보기

댓글 영역