최종 목표
아키텍처가 만족해야 할 것
| 목표 | 의미 |
|---|
| 정합성 | 패킷 처리 순서/상태 전이가 일관되게 유지됨 |
| 안정성 | 종료/실패/late completion 경로에서도 크래시 없이 동작 |
| 확장성 | 동접 증가 시 구조를 유지한 채 튜닝 가능 |
| 생산성 | 컨텐츠 개발자는 네트워크 저수준 대신 게임 로직에 집중 가능 |
핵심 원칙
- 엔진과 컨텐츠의 경계를 코드 레벨로 분리
- Register/Process 루프를 모든 I/O 경로에서 일관되게 유지
- 수명(refcount) + 상태 전이(idempotent disconnect) 동시 관리
계층 구조(Engine vs Content)
책임 분리
| 계층 | 담당 |
|---|
| Engine Core | IocpCore, Listener, Session, ReceiveBuffer, SendBuffer, PacketSession |
| Content | GameSession, PacketHandler, 게임 규칙/월드 상태 |
의존 방향
- Content -> Engine 사용은 허용
- Engine -> Content 직접 의존은 금지(
SessionFactory/콜백으로 역전)
효과
- 엔진 재사용성 확보
- 컨텐츠 변경이 네트워크 코어를 오염시키지 않음
런타임 데이터 흐름
flowchart LR
A[AcceptEx 완료] --> B[Listener::ProcessAccept]
B --> C[Service::CreateSession + IOCP Register]
C --> D[Session::RegisterRecv]
D --> E[GQCS 완료]
E --> F[Session::ProcessRecv]
F --> G[PacketSession::OnRecv]
G --> H[PacketHandler 분기]
H --> I[Game Logic / JobQueue]
I --> J[SendBuffer enqueue]
J --> K[Session::RegisterSend]
K --> L[ProcessSend]
요약
- "접속 수락 -> 세션 연결 -> 수신 조립 -> 패킷 분기 -> 로직 -> 송신"이 한 사이클입니다.
반복 핵심
- Recv/Accept는 처리 후 재등록
- Send는 큐 드레인 동안 연속 등록
멀티스레드와 소유권 모델
스레드 역할
| 구간 | 스레드 | 설계 포인트 |
|---|
| Dispatch | IOCP 워커 풀 | 완료 이벤트 병렬 처리 |
| Recv | 세션당 보통 1 outstanding | 순서/경합 단순화 |
| Send | 다중 호출 가능 | sendQueue + atomic 플래그 필요 |
소유권 규칙
- I/O 이벤트는 완료 전까지
owner shared_ptr로 Session 생존 보장
- 완료 후
owner reset으로 참조 해제
- 종료 중 late completion은 상태 플래그와 함께 정리
데드락 회피
- 락 보유 상태에서 네트워크 API 호출 최소화
- 재등록은 가능하면 락 밖에서 수행
패킷 처리 아키텍처
구성
| 단계 | 역할 |
|---|
PacketHeader(Size+ID) | 프레이밍/분기 기준 |
PacketSession | 스트림 -> 완전체 패킷 조립 |
PacketHandler | ID 기반 핸들러 라우팅 |
| ProtoBuf/ReaderWriter | payload 직렬화 계약 |
안전 규칙
size 최소/최대 검증
- unknown ID 정책(드롭/종료) 명시
- 직렬화/역직렬화 순서 불일치 금지
운영 규칙
- 파싱 실패 사유 로그 표준화
- 버전 불일치 지표 수집
컨텐츠 개발자 워크플로우
일반 순서
.proto 또는 패킷 구조 정의
PacketHandler에 ID 매핑 추가
GameSession::OnRecvPacket 또는 핸들러에서 로직 연결
Make_* 함수로 송신 패킷 생성 후 Send
컨텐츠가 신경 쓸 것
- 비즈니스 규칙, 검증, 게임 상태 변경
- 네트워크 코어 동작(Register/Dispatch/버퍼 내부)은 엔진에 위임
흔한 실수
- 코어를 우회해 소켓 직접 접근
- 파싱 실패를 무시하고 로직 진행
최종 운영 체크포인트
필수 관측 지표
- 세션 수/접속률/Disconnect 사유
- sendQueue 길이/부분 전송 발생률
- parse 실패율/unknown ID 비율
- Recv 재등록 누락 징후(세션 정체)
장애 시 우선 점검 순서
- 재등록 누락 여부(Recv/Accept/Send)
sendRegistered stuck 여부
- owner 해제 누락/댕글링 여부
- 헤더 검증/파싱 실패 로그
핵심 문장
좋은 IOCP 엔진은 "빠른 코드"보다 "실패 경로가 끊기지 않는 코드"로 완성됩니다.
전체 정리
CreateIoCompletionPort -> Register -> Dispatch는 뼈대입니다.
Reference Counting + 상태 전이는 생존성입니다.
ReceiveBuffer + SendBuffer는 성능과 정합성의 기반입니다.
PacketHeader + PacketSession + PacketHandler + ProtoBuf는 확장 가능한 프로토콜 계층입니다.