1. Session 클래스 분석
Session.h (헤더 파일)
클래스 선언부
class Session : public IocpObject
{
friend class Listener;
friend class IocpCore;
friend class Service;
Session 클래스는 IocpObject를 상속받으며, IOCP(입출력 완료 포트) 기반 비동기 통신을 처리하는 핵심 클래스입니다.
friend 선언을 통해 Listener, IocpCore, Service 클래스가 Session의 private 및 protected 멤버에 접근할 수 있게 됩니다.
생성자와 소멸자
public:
Session();
virtual ~Session();
- 생성자: 소켓을 생성합니다.
- 소멸자: 세션이 파괴될 때 소켓을 닫아 리소스를 정리합니다.
연결 관리 함수
void Disconnect(const WCHAR* cause);
bool IsConnected() { return _connected; }
Disconnect: 세션을 비활성화하며 연결을 끊고 소켓을 닫습니다.
_connected: 현재 세션이 연결되었는지를 나타내는 Atomic<bool>입니다.
서비스 및 네트워크 정보 관리
shared_ptr<Service> GetService() { return _service.lock(); }
void SetService(shared_ptr<Service> service) { _service = service; }
void SetNetAddress(NetAddress address) { _netAddress = address; }
NetAddress GetAddress() { return _netAddress; }
SOCKET GetSocket() { return _socket; }
_service: Session이 속한 Service 클래스의 약한 참조입니다.
_netAddress: 네트워크 주소 정보를 저장합니다.
_socket: 네트워크 연결에 사용되는 소켓 핸들입니다.
IOCP 이벤트 관련 함수
virtual HANDLE GetHandle() override;
virtual void Dispatch(class IocpEvent* iocpEvent, int32 numOfBytes = 0) override;
GetHandle: IOCP에 등록할 수 있도록 소켓 핸들을 반환합니다.
Dispatch: IOCP 이벤트를 처리하며, 이벤트의 타입에 따라 적절한 Process 함수를 호출합니다.
가상 함수 (컨텐츠 코드 오버라이딩용)
virtual void OnConnected() { }
virtual int32 OnRecv(BYTE* buffer, int32 len) { return len; }
virtual void OnSend(int32 len) { }
virtual void OnDisconnected() { }
- 확장 포인트:
Session을 상속받는 클래스에서 오버라이드하여 사용자 정의 로직을 추가할 수 있습니다.
OnConnected: 연결되었을 때 호출.
OnRecv: 데이터를 수신했을 때 호출.
OnSend: 데이터를 송신했을 때 호출.
OnDisconnected: 연결이 종료되었을 때 호출.
전송 관련 함수
void RegisterRecv();
void ProcessRecv(int32 numOfBytes);
RegisterRecv: 비동기 수신을 IOCP에 등록합니다.
ProcessRecv: 데이터 수신 이벤트가 완료되었을 때 호출됩니다.
Session.cpp (구현 파일)
생성자와 소멸자
Session::Session()
{
_socket = SocketUtils::CreateSocket();
}
Session::~Session()
{
SocketUtils::Close(_socket);
}
- 생성자:
SocketUtils::CreateSocket()을 사용하여 소켓을 생성합니다.
- 소멸자: 소켓이 더 이상 필요 없으면 닫아줍니다.
Disconnect 함수
void Session::Disconnect(const WCHAR* cause)
{
if (_connected.exchange(false) == false)
return;
wcout << "Disconnect : " << cause << endl;
OnDisconnected();
SocketUtils::Close(_socket);
GetService()->ReleaseSession(GetSessionRef());
}
_connected.exchange(false): 세션의 연결 상태를 원자적으로 변경합니다.
OnDisconnected: 사용자 정의 로직 호출.
ReleaseSession: Service에서 세션을 제거하여 Reference Count를 감소시킵니다.
Dispatch 함수
void Session::Dispatch(IocpEvent* iocpEvent, int32 numOfBytes)
{
switch (iocpEvent->eventType)
{
case EventType::Connect:
ProcessConnect();
break;
case EventType::Recv:
ProcessRecv(numOfBytes);
break;
case EventType::Send:
ProcessSend(numOfBytes);
break;
default:
break;
}
}
- IOCP 이벤트의
eventType에 따라 Connect, Recv, Send 이벤트를 처리합니다.
RegisterRecv 함수
void Session::RegisterRecv()
{
if (IsConnected() == false)
return;
_recvEvent.Init();
_recvEvent.owner = shared_from_this();
WSABUF wsaBuf;
wsaBuf.buf = reinterpret_cast<char*>(_recvBuffer);
wsaBuf.len = len32(_recvBuffer);
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;
}
}
}
WSARecv: 비동기 수신을 등록합니다.
- 에러가 발생하면 HandleError를 통해 오류를 처리하고
owner 참조를 해제합니다.
ProcessRecv 함수
void Session::ProcessRecv(int32 numOfBytes)
{
_recvEvent.owner = nullptr;
if (numOfBytes == 0)
{
Disconnect(L"Recv 0");
return;
}
cout << "Recv Data Len = " << numOfBytes << endl;
RegisterRecv();
}
numOfBytes == 0: 연결이 종료되었음을 의미. Disconnect 호출.
- 정상적인 데이터 수신 후, 다시
RegisterRecv를 호출하여 수신 이벤트를 재등록합니다.
2. Service와 Listener에서의 Session 사용
Service.cpp (Session 생성 및 관리)
CreateSession 함수
SessionRef Service::CreateSession()
{
SessionRef session = _sessionFactory();
session->SetService(shared_from_this());
if (_iocpCore->Register(session) == false)
return nullptr;
return session;
}
Service는 SessionFactory를 사용하여 Session 객체를 생성합니다.
- 생성된 세션을 IOCP에 등록합니다.
AddSession 및 ReleaseSession 함수
void Service::AddSession(SessionRef session)
{
WRITE_LOCK;
_sessionCount++;
_sessions.insert(session);
}
void Service::ReleaseSession(SessionRef session)
{
WRITE_LOCK;
assert(_sessions.erase(session) != 0);
_sessionCount--;
}
AddSession: 새로운 세션을 등록하고 세션 수를 증가시킵니다.
ReleaseSession: 세션을 제거하고 세션 수를 감소시킵니다.
Listener.cpp (Session 연결 및 Accept 처리)
ProcessAccept 함수
void Listener::ProcessAccept(IocpEvent* acceptEvent)
{
SessionRef session = acceptEvent->session;
session->SetNetAddress(NetAddress(sockAddress));
session->ProcessConnect();
RegisterAccept(acceptEvent);
}
AcceptEvent의 세션을 가져와 ProcessConnect를 호출합니다.
RegisterAccept를 호출하여 다음 연결을 대기합니다.
3. GameServer에서의 흐름
GameServer.cpp (메인 함수)
ServerServiceRef service = make_shared<ServerService>(
NetAddress(L"127.0.0.1", 7777),
make_shared<IocpCore>(),
[]() { return make_shared<GameSession>(); },
100);
- ServerService는
GameSession을 생성하는 SessionFactory를 사용합니다.
Dispatch를 통해 Session 이벤트를 IOCP를 기반으로 처리합니다.