| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
Tags
- Prisma
- Behavior Design Pattern
- 자바스크립트
- 2-SAT
- PROJECT
- SCC
- 게임 서버 아키텍처
- 이분 탐색
- DP
- reference counting
- JavaScript
- trie
- 최소 공통 조상
- Strongly Connected Component
- Binary Lifting
- 비트필드를 이용한 dp
- Spin Lock
- ccw 알고리즘
- 트라이
- statefulset
- select 모델
- map
- HTTP
- 강한 연결 요소
- 벨만-포드
- Delete
- 그래프 탐색
- Overlapped Model
- Github
- Lock-free Stack
Archives
- Today
- Total
dh_0e
[C++ Server] PacketSession 본문
PacketSession
- Session 클래스(TCP 소켓의 기본 송수신을 담당)를 상속받아 패킷 조립 기능을 얹은 클래스
- TCP 특성상 패킷이 모두 도착했다는 보장을 할 수가 없는 TCP 데이터 경계 문제(TCP Boundary Problem)를 해결함
- TCP는 스트림(Stream) 기반이라 데이터의 경계가 없음
- 패킷이 쪼개져서 오기도 하고(Fragmentation), 뭉쳐서 오기도 함(Sticky Packets)
struct PacketHeader {
uint16 size;
uint16 id;
};
- size(2Byte) + id(2Byte)로 구성된 헤더를 만듦
- size: 패킷 전체 크기 (header + data)
- id: 프로토콜 ID (ex. 1=로그인, 2=회원가입)
- OnRecv (final)
- 네트워크 I/O 스레드에서 실제 데이터를 수신했을 때 호출되는 함수
- 역할
- 패킷 쪼개짐/뭉침 문제를 모두 처리
- 받은 데이터 버퍼를 읽으면서 헤더의 size만큼 데이터가 다 모였는지 확인
- 다 모이지 않았다면 다음 수신을 기다림
- 다 모였다면 온전한 하나의 패킷을 잘라내어 OnRecvPacket() 호출
- final: 하위 클래스에서 실수로 재정의하는 것을 방지
- OnRecvPacket (abstract)
- OnRecv에서 온전한 1개의 패킷이 조립되었을 때마다 호출
- 역할
- 클래스를 상속받을 실제 게임 세션에서 컨텐츠 로직을 구현하는 곳 (원래 OnRecv 역할)
- 넘어온 데이터가 무조건 결함 없는 1개의 완벽한 패킷이기 때문에, 헤더의 id를 읽고 컨텐츠 처리
- GetPacketSessionRef
- 멀티스레드 환경에서 세션 객체의 생명 주기를 안전하게 관리하기 위해 shared_from_this 반환
Session.h
/*--------------------
PacketSession
--------------------*/
// TCP 특성상 패킷이 모두 도착했다는 보장을 할 수가 없어서 이를 처리하는 세션
struct PacketHeader {
uint16 size;
uint16 id;
};
// [size(2Byte)][id(2Byte)][data...]
// size: 패킷 전체 크기 (header + data)
// id: 프로토콜 ID (ex. 1=로그인, 2=회원가입)
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) final;
virtual int32 OnRecvPacket(BYTE* buffer, int32 len) abstract;
};
Session.cpp
/*--------------------
PacketSession
--------------------*/
PacketSession::PacketSession() {}
PacketSession::~PacketSession() {}
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;
}
DummyClient.cpp / GameServer.cpp / GameSession.h / GameSession.cpp / Types.h 수정
PacketSession, Disconnect Logic Debug · znfnfns0365/CPP_Server_Practice@c305ec7
+ MakeShared<ClientService>(NetAddress(L"127.0.0.1", 7777), MakeShared<IocpCore>(), MakeShared<ServerSession>, 1000);
github.com
- DummyClient.cpp
- OnRecv를 OnRecvPacket으로 바꾸고, OnRecv에서 받은 패킷을 복사, 출력
- 클라이언트 1000개를 만들어 서버 연결 시도
- GameServer.cpp / GameSession.cpp: Broadcast를 GameServer에서 주기적으로(250ms) 보내도록 수정
- GameSession.h: GameSession이 PacketSession을 상속, OnRecv가 아닌 OnRecvPacket을 재정의 하도록 수정
- Types.h: PacketSessionRef 선언
Session.cpp 수정 (Line 43~43 → Line 230~232)
- 원래 코드에서 Client를 1000개로 늘려서 실행 중 Client를 접속 해제(종료)하면 CRASH 발생

- 이유: 원래 코드의 로직으로 GameSession::OnRecvPacket에서 Send 처리 중 클라이언트가 접속 해제 시
- Session::RegisterSend()에서 WSASend 중 HandleError 발생
- Session::HandleError()에서 Disconnect(L"HandleError"); 호출
- Session::Disconnect()에서 OnDisconnected() 호출
- GameSession::OnDisconnected()에서 세션 삭제
- Send 처리 중 세션을 삭제한다는 뜻 → CRASH (Dangling Pointer) 발생

- 다음과 같이 OnDisconnected() 호출 부분을 ProcessDisconnect()로 옮겨서 GameSession이 소멸된 이후에 세션을 삭제하게끔 만들어줌
- 기존 (위험): Send 하다가 에러 발생 → 그 즉시 ReleaseSession 호출 → 메모리 해제
- 수정 (안전): 에러 발생 → RegisterDisconnect (끊어달라고 통보만 함) → 나중에 IOCP가 완료 신호를 주면 ProcessDisconnect에서 정리

'C++ Server > Framework' 카테고리의 다른 글
| [C++ Server] Packet Handler (0) | 2026.05.09 |
|---|---|
| [C++ Server] Buffer Helper (Reader, Writer) (0) | 2026.05.08 |
| [C++ Server] SendBuffer (+GameSession) (0) | 2026.05.06 |
| [C++ Server] RecvBuffer (0) | 2026.05.05 |
| [C++ Server] IOCP 기반 Session 및 비동기 연결 관리 (0) | 2026.04.30 |