Session.h, Session.cpp
...
/*----------------
PacketSession
----------------*/
struct PacketHeader
{
uint16 size;
uint16 id; // 프로토콜ID (ex. 1=로그인, 2=이동요청)
};
// [size(2)][id(2)][data...]...[size(2)][id(2)][data...]
class PacketSession : public Session
{
public:
PacketSession();
virtual ~PacketSession();
PacketSessionRef GetPacketSessionRef() { return static_pointer_cast<PacketSession>(shared_from_this()); }
protected:
virtual int32 OnRecv(BYTE* buffer, int32 len) sealed;
virtual int32 OnRecvPacket(BYTE* buffer, int32 len) abstract;
};
...
void Session::Send(SendBufferRef sendBuffer)
{
if (IsConnected() == false)
return;
bool registerSend = false;
// 현재 RegisterSend가 걸리지 않은 상태라면, 걸어준다
{
WRITE_LOCK;
_sendQueue.push(sendBuffer);
if (_sendRegistered.exchange(true) == false)
registerSend = true;
}
if (registerSend)
RegisterSend();
}
...
void Session::Disconnect(const WCHAR* cause)
{
if (_connected.exchange(false) == false)
return;
// TEMP
wcout << "Disconnect : " << cause << endl;
RegisterDisconnect();
}
...
void Session::ProcessDisconnect()
{
_disconnectEvent.owner = nullptr; // RELEASE_REF
OnDisconnected(); // 컨텐츠 코드에서 오버라이딩
GetService()->ReleaseSession(GetSessionRef());
}
...
/*----------------
PacketSession
----------------*/
PacketSession::PacketSession()
{
}
PacketSession::~PacketSession()
{
}
// [size(2)][id(2)][data...]...[size(2)][id(2)][data...]
int32 PacketSession::OnRecv(BYTE* buffer, int32 len)
{
int32 processLen = 0;
while (true)
{
int32 dataSize = len - processLen;
// 최소한 헤더는 파싱할 수 있어야 한다.
if (dataSize < sizeof(PacketHeader))
break;
PacketHeader header = *(reinterpret_cast<PacketHeader*>(&buffer[processLen]));
// 헤더에 기록된 패킷 크기를 파싱할 수 있어야 한다.
if (dataSize < header.size)
break;
// 패킷 조립 성공
OnRecvPacket(&buffer[processLen], header.size);
processLen += header.size;
}
return processLen;
}
GameSession.h, GameSession.cpp
...
class GameSession : public PacketSession
{
public:
~GameSession()
{
cout << "~GameSession" << endl;
}
virtual void OnConnected() override;
virtual void OnDisconnected() override;
virtual int32 OnRecvPacket(BYTE* buffer, int32 len) override;
virtual void OnSend(int32 len) override;
};
...
int32 GameSession::OnRecvPacket(BYTE* buffer, int32 len)
{
PacketHeader header = *((PacketHeader*)&buffer[0]);
cout << "Packet ID : " << header.id << "Size : " << header.size << endl;
return len;
}
...
GameServer.cpp
...
#include "GameSessionManager.h"
int main()
{
...
char sendData[1000] = "Hello World";
while (true)
{
SendBufferRef sendBuffer = GSendBufferManager->Open(4096);
BYTE* buffer = sendBuffer->Buffer();
((PacketHeader*)buffer)->size = (sizeof(sendData) + sizeof(PacketHeader));
((PacketHeader*)buffer)->id = 1; // 1 : Hello Msg
::memcpy(&buffer[4], sendData, sizeof(sendData));
sendBuffer->Close((sizeof(sendData) + sizeof(PacketHeader)));
GSessionManager.Broadcast(sendBuffer);
this_thread::sleep_for(250ms);
}
}
DummyClient.cpp
...
class ServerSession : public PacketSession
{
...
virtual void OnConnected() override
{
//cout << "Connected To Server" << endl;
}
virtual int32 OnRecvPacket(BYTE* buffer, int32 len) override
{
PacketHeader header = *((PacketHeader*)&buffer[0]);
//cout << "Packet ID : " << header.id << "Size : " << header.size << endl;
char recvBuffer[4096];
::memcpy(recvBuffer, &buffer[4], header.size - sizeof(PacketHeader));
cout << recvBuffer << endl;
return len;
}
virtual void OnSend(int32 len) override
{
//cout << "OnSend Len = " << len << endl;
}
virtual void OnDisconnected() override
{
//cout << "Disconnected" << endl;
}
};
1. Session::Send 효율적이지 못한 부분은?
- 어느 한 쓰레드가 RegisterSend 호출 중 이라면 WriteLock에서 다른 많은 Send 요청이 대기 할 수 있음.
2. PacketSession 이 필요한 이유는?
- 보낸 모든 데이터를 한 번에 받는 다는 보장이 없는 TCP 특성 때문에, 데이터 모두 받았음을 확인 할 수 있는 수단이 필요.
3. PacketSession::OnRecv에서 header가 덜 들어왔거나 header만 들어온 상황은 어떻게 처리하지?
- RegisterRecv() > ProcessRecv() 호출 되면서 아직 들어오지 않은 부분 들어옴.
4. 접속 Client의 개수를 1000개로 늘리면, server broadcast에서 crash 나는 이유는 그리고 해결방법?
- sessions iterate 하다가 sessions 에 변화가 생겨서 남. OnDisconnect에서 session remove하고 있음.
- 해결방법 : Disconnect에서 session remove하지 않고 ProcessDisconnect에서 한다.
PacketHandler (0) | 2023.05.06 |
---|---|
Buffer Helpers (0) | 2023.04.19 |
SendBuffer Pooling (0) | 2023.04.05 |
SendBuffer (0) | 2021.12.21 |
RecvBuffer (0) | 2021.12.20 |
댓글 영역