버퍼자체는 쉽기에 아래를 보면되고,
#pragma once
/*--------------
RecvBuffer
----------------*/
class RecvBuffer
{
enum { BUFFER_COUNT = 10 };
public:
RecvBuffer(int32 bufferSize);
~RecvBuffer();
void Clean();
bool OnRead(int32 numOfBytes);
bool OnWrite(int32 numOfBytes);
BYTE* ReadPos() { return &_buffer[_readPos]; }
BYTE* WritePos() { return &_buffer[_writePos]; }
int32 DataSize() { return _writePos - _readPos; }
int32 FreeSize() { return _capacity - _writePos; }
private:
int32 _capacity = 0;
int32 _bufferSize = 0;
int32 _readPos = 0;
int32 _writePos = 0;
Vector<BYTE> _buffer;
};
#include "pch.h"
#include "RecvBuffer.h"
/*--------------
RecvBuffer
----------------*/
RecvBuffer::RecvBuffer(int32 bufferSize) : _bufferSize(bufferSize)
{
_capacity = bufferSize * BUFFER_COUNT;
_buffer.resize(_capacity);
}
RecvBuffer::~RecvBuffer()
{
}
void RecvBuffer::Clean()
{
int32 dataSize = DataSize();
if (dataSize == 0)
{
// 딱 마침 읽기+쓰기 커서가 동일한 위치라면, 둘 다 리셋.
_readPos = _writePos = 0;
}
else
{
// 여유 공간이 버퍼 1개 크기 미만이면, 데이터를 앞으로 땅긴다.
if (FreeSize() < _bufferSize)
{
::memcpy(&_buffer[0], &_buffer[_readPos], dataSize);
_readPos = 0;
_writePos = dataSize;
}
}
}
bool RecvBuffer::OnRead(int32 numOfBytes)
{
if (numOfBytes > DataSize())
return false;
_readPos += numOfBytes;
return true;
}
bool RecvBuffer::OnWrite(int32 numOfBytes)
{
if (numOfBytes > FreeSize())
return false;
_writePos += numOfBytes;
return true;
}
어떻게 사용되는지 확인하자
void Session::RegisterRecv()
{
if (IsConnected() == false)
return;
_recvEvent.Init();
_recvEvent.owner = shared_from_this(); // ADD_REF
WSABUF wsaBuf;
wsaBuf.buf = reinterpret_cast<char*>(_recvBuffer.WritePos());
wsaBuf.len = _recvBuffer.FreeSize();
DWORD numOfBytes = 0;
DWORD flags = 0;
if (SOCKET_ERROR == ::WSARecv(_socket, &wsaBuf, 1, OUT &numOfBytes, OUT &flags, &_recvEvent, nullptr))
{
int32 errorCode = ::WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
HandleError(errorCode);
_recvEvent.owner = nullptr; // RELEASE_REF
}
}
}
void Session::ProcessRecv(int32 numOfBytes)
{
_recvEvent.owner = nullptr; // RELEASE_REF
if (numOfBytes == 0)
{
Disconnect(L"Recv 0");
return;
}
if (_recvBuffer.OnWrite(numOfBytes) == false)
{
Disconnect(L"OnWrite Overflow");
return;
}
int32 dataSize = _recvBuffer.DataSize();
int32 processLen = OnRecv(_recvBuffer.ReadPos(), dataSize); // 컨텐츠 코드에서 재정의
if (processLen < 0 || dataSize < processLen || _recvBuffer.OnRead(processLen) == false)
{
Disconnect(L"OnRead Overflow");
return;
}
// 커서 정리
_recvBuffer.Clean();
// 수신 등록
RegisterRecv();
}