Session 기초

Jaemyeong Lee·2025년 3월 22일

게임 서버1

목록 보기
144/220

Session의 역할과 경계

한 줄 정의

Session은 "클라이언트 1개 연결의 네트워크 상태와 I/O 파이프라인"을 대표하는 객체입니다.

Session이 담당하는 일

담당설명
송수신 파이프라인RegisterRecv/ProcessRecv, Send/ProcessSend
연결 상태Connected/Disconnecting 같은 상태 전이 관리
주소/식별 정보원격 주소, 세션 ID, 통계
이벤트 콜백 브릿지OnRecv, OnDisconnected 등을 컨텐츠로 전달

Session이 하지 말아야 할 일

  • 전투 판정, AI, 퀘스트 같은 게임 규칙 처리
  • DB 직접 접근(로직/DB 파이프라인을 우회하는 구조)
  • 전역 공유 상태 직접 수정(락 폭발 원인)

상태 전이(State Machine)

권장 상태

enum class SessionState
{
    Disconnected,
    Connecting,     // 클라이언트 모드에서 사용 가능
    Connected,
    Disconnecting
};

전이 예시

이벤트전이
Accept/Connect 완료Disconnected -> Connected
Disconnect 시작Connected -> Disconnecting
정리 완료Disconnecting -> Disconnected

핵심 규칙

  • Disconnectidempotent(여러 번 호출돼도 한 번처럼 동작)하게 설계하세요.
  • 상태 전이는 CAS/락으로 보호해서 중복 종료를 막아야 합니다.

IocpObject 상속과 Dispatch

왜 상속하는가

  • Session도 IOCP 완료 이벤트를 직접 받는 대상입니다.
  • 따라서 GetHandleDispatch를 구현해 이벤트를 내부 처리 함수로 분기해야 합니다.

Dispatch 예시

void Session::Dispatch(IocpEvent* event, int32 numOfBytes)
{
    switch (event->eventType)
    {
    case EventType::Recv:       ProcessRecv(event, numOfBytes); break;
    case EventType::Send:       ProcessSend(event, numOfBytes); break;
    case EventType::Connect:    ProcessConnect(event, numOfBytes); break;
    case EventType::Disconnect: ProcessDisconnect(event, numOfBytes); break;
    default: break;
    }
}

분기 시 주의

  • numOfBytes == 0(Recv)은 일반적으로 원격 정상 종료 신호로 처리합니다.
  • 실패 완료(GQCS FALSE && ov != nullptr)도 이벤트 타입 기준 정리 경로로 흘려야 합니다.

외부 인터페이스 설계

대표 API

함수용도호출 주체
Send(buffer)송신 요청 enqueue/등록게임 로직/서비스
Connect()클라이언트 모드 접속 시작클라이언트 서비스
Disconnect(reason)연결 종료 시작모든 계층
IsConnected(), GetAddress()상태/정보 조회로깅/관리 코드

API 계약(Contract)

  • Send는 보통 "즉시 전송 완료"가 아니라 "전송 요청 수락" 의미입니다.
  • 연결 종료 진행 중(Disconnecting)에는 신규 Send를 거부하는 정책이 안전합니다.
  • Disconnect 호출 후 콜백(OnDisconnected)이 늦게 올 수 있음을 계약에 명시해야 합니다.

가상 콜백과 스레드 경계

콜백 포인트

함수호출 시점일반 용도
OnConnected연결 확정 직후인증 시작, 초기 패킷 전송
OnRecv유효 데이터 수신 시패킷 파싱/Job 생성
OnSend송신 완료 시송신 통계/후속 전송
OnDisconnected종료 정리 직후세션 제거, 리소스 정리

스레드 경계 원칙

  • 이 콜백들은 보통 네트워크 워커 스레드에서 호출됩니다.
  • 무거운 게임 로직은 콜백에서 직접 실행하지 말고 JobQueue로 넘기세요.

재진입 주의

  • OnDisconnected 안에서 다시 Disconnect를 호출해도 안전해야 합니다.
  • 콜백 내에서 Session 소멸을 강제하면 완료 이벤트와 레이스가 날 수 있습니다.

Send/Recv 파이프라인 요약

Recv 루프

RegisterRecv -> ProcessRecv -> OnRecv -> RegisterRecv

  • 이 루프가 한 번 끊기면 해당 세션은 더 이상 수신하지 못합니다.

Send 루프

Send enqueue -> (필요 시) RegisterSend -> ProcessSend -> 남은 데이터 확인 -> 재등록

  • 세션별 송신 큐 + 전송 중 플래그를 사용하면 동시 Send 경합을 줄일 수 있습니다.

부분 전송/부분 수신

  • Send/Recv는 한 번에 원하는 크기를 모두 처리한다는 보장이 없습니다.
  • 누적 버퍼/패킷 프레이밍 로직을 Session 계층에 명시적으로 둬야 합니다.

강의 시 유의사항

강조 포인트

  • Session은 "소켓 래퍼"가 아니라 "연결 생명주기 관리자"입니다.
  • Listener(접속 파이프라인)와 Session(연결 파이프라인)을 역할별로 분리해 설명하세요.
  • Part 6(레퍼런스 카운팅)과 이어서 "수명 보장 없으면 Session은 반드시 터진다"를 강조하세요.

자주 하는 오해

오해바로잡기
Send() 호출하면 바로 전송 완료다대부분 "전송 요청 등록"이다
OnRecv에서 게임 로직을 직접 돌려도 된다워커 스레드 블로킹으로 전체 처리량이 떨어진다
Disconnect는 한 번만 호출된다실전에서는 중복 호출을 항상 가정해야 안전하다

체크 질문 (스스로 답해보기)

  • Session 상태 전이를 원자적으로 보장하지 않으면 어떤 버그가 나는가?
  • OnRecv에서 바로 로직을 실행하지 않고 JobQueue로 넘기는 이유는 무엇인가?
  • Recv 재등록이 누락됐는지 운영 중 어떤 지표/증상으로 감지할 수 있는가?

profile
李家네_공부방

0개의 댓글