1. Session 클래스 분석

Session.h (헤더 파일)

클래스 선언부

class Session : public IocpObject
{
    friend class Listener;
    friend class IocpCore;
    friend class Service;
  • Session 클래스는 IocpObject를 상속받으며, IOCP(입출력 완료 포트) 기반 비동기 통신을 처리하는 핵심 클래스입니다.
  • friend 선언을 통해 Listener, IocpCore, Service 클래스가 Sessionprivateprotected 멤버에 접근할 수 있게 됩니다.

생성자와 소멸자

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(); // ADD_REF

    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; // RELEASE_REF
        }
    }
}
  • WSARecv: 비동기 수신을 등록합니다.
  • 에러가 발생하면 HandleError를 통해 오류를 처리하고 owner 참조를 해제합니다.

ProcessRecv 함수

void Session::ProcessRecv(int32 numOfBytes)
{
    _recvEvent.owner = nullptr; // RELEASE_REF

    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;
}
  • ServiceSessionFactory를 사용하여 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);
  • ServerServiceGameSession을 생성하는 SessionFactory를 사용합니다.
  • Dispatch를 통해 Session 이벤트를 IOCP를 기반으로 처리합니다.

profile
李家네_공부방

0개의 댓글