[C++] IOCP를 활용한 채팅 서버 구현
·
Study/C++ & C#
문제 정의 채팅 서버 구현을 위해 해결해야 할 사항들 목표 유니티 프로젝트에 외부 서버를 사용한 채팅 기능 구현. 목표가 아닌 것 게임 로직을 Server-Driven 하게 전면 재작성. 지금 당장의 목표는 아니지만 할 필요는 있음. 구현을 위한 순서 디자인 결정 패킷 설계 채팅 로직 구현 C++ 더미 채팅 클라이언트로 테스트 C# 더미 채팅 클라이언트로 테스트 유니티 프로젝트에 실장 1. 디자인 결정 서버 세션에 여러 클라이언트가 접속해 있고, 이 세션 안에서 PartySession이라는 부분집합을 구현한다. PartySession에만 Broadcast 되는 정보는 외부의 다른 클라이언트에겐 닿지 않는다. 그러나 PartySession은 서버 세션 전체에 Broadcast 되는 정보는 받을 수 있다. ..
[C++/Python] 패킷 자동화
·
Study/C++ & C#
패킷의 변동 사항과 관련해 그와 관련된 부분을 일일이 수정하는 것은 매우 번거롭고 실수가 잦을 수 있는 일일 것이다. 하지만 자동화한다면 실수도 줄 것이고 개발이 보다 편리해질 것이라 기대할 수 있겠다. 자동화하는 과정을 배워보자. 1. proto 파일 관리 사실 이전에 proto 파일을 작성한 것처럼 모든 구조체를 하나에 때려 박는 것은 좋은 선택이 아니다. 프로토콜, 구조체, 열거형 등등을 각자의 특성에 맞게 나눠서 관리하면 더 직관적일 것이다. 열거형부터 정의해 보자. syntax = "proto3"; package Protocol; enum PlayerType { // 항상 0번이 있어야 하기 때문에 NONE 등을 0으로 하는 걸 추천 PLAYER_TYPE_NONE = 0; PLAYER_TYPE_..
[C++] Protobuf
·
Study/C++ & C#
Protocol Buffers(Protobuf) 는 실제 라이브 서비스에서도 많이 쓰이는 직렬화 메커니즘이다. 프로토 버프를 프로젝트에 올려가면서 직렬화에 대해 공부했던 내용과 비교하며 익혀보자. 1. 다운로드 protobuf는 공식 Github Repo에서 받을 수 있다. 릴리즈 페이지로 가서 아래의 파일을 다운해야 한다. 지금은 최신 버전이 아니라 구버전을 사용할 것이다. 저 파일을 받아주자. 뒤의 c는 컴파일러라는 의미이다. 구조를 던져주면 그걸 컴파일하여 자동으로 코드를 생성해 준다고 생각해도 될 것이다. 저 파일을 다운 받아서 적당한 곳에 압축을 풀어주자. 압축을 풀고 나서 bin 폴더 안에 보면 exe 파일 하나만 덩그러니 있을 것이다. 그 파일이 소스코드를 자동으로 만들어 줄 것이다. 2. ..
[C++] Packet Serialization
·
Study/C++ & C#
직렬화라는 개념은 통신에서만 중요한 것이 아니다. 파일 입출력을 할 때도 매우 중요한 개념이다. 하지만 지금 공부하는 부분은 서버이기 때문에 통신에 있어서의 패킷 직렬화에 대해 알아보자. 1. 패킷 직렬화란? 메모리에 있는 데이터를 패킷에 일렬로 차곡차곡 쌓아 하나의 바이트 배열로 만드는 것을 패킷 직렬화라고 한다. 어 그렇다면 우리가 기존에 버퍼에 데이터를 넣어 보내던 것도 패킷 직렬화가 아닌가? PacketHeader* header = bw.Reserve(); // id(uint64), 체력(uint32), 공격력(uint16) bw > hp >> attack; 다시 우리가 활용할 수 있는 형태로 이렇게 빼서 저장하면 역직렬화(Deserialization) 한 것이다. 지금까지 우리가 한 것들은 기초..
[C++] Unicode / Encoding
·
Study/C++ & C#
가변 길이 데이터를 다루는 데 있어서 문자열은 매우 중요한 요소 중 하나라고 할 수 있을 것이다. 문자 집합이 뭔지, 인코딩이 뭔지에 대해서 정리해 보고 실제로 코드를 작성해 보자. 1. 익숙한 친구들부터 우리는 문자를 표현하기 위해 처음 프로그래밍을 배울 때부터 「char」라는 자료형을 써왔다. 익숙하지만 데이터를 어떻게 저장하는지에 대해서 깊게 고민해 본 사람이 얼마나 될까? 어떤 문자 집합을 사용하는지, 애초에 문자 집합과 인코딩을 제대로 구분하는 사람이 일반적으론 드문 것 같다. 아래의 다양한 자료형의 문자열을 통해 알아보자. char sendData[1000] = "가"; char sendData1[1000] = u8"가"; WCHAR sendData2[1000] = L"가"; TCHAR sen..
[C++] Packet Handler
·
Study/C++ & C#
클라이언트와 서버는 많은 종류의 패킷으로 통신하게 될 것이다. 각 패킷 ID(OPCODE) 별로 일일이 분기시키고, 반복된 코드를 계속 작성하게 된다면 매우 비효율적일 것이다. 패킷을 보다 효율적으로 관리할 수 있게 해 줄 핸들러 클래스를 작성한다. 1. 클래스 작성 서버 클라 양쪽에 핸들러를 만들어 둘 것이다. 1-1. Client #pragma once enum { S_TEST = 1 }; class ClientPacketHandler { public: static void HandlePacket(BYTE* buffer, int32 len); static void Handle_S_TEST(BYTE* buffer, int32 len); }; ID 열거형의 네임 컨벤션은 아래와 같다. S_TEST - (..
[C++] Buffer Helpers
·
Study/C++ & C#
2023.07.08 수정 rValue Ref와 Universal Ref가 혼동된 부분 수정. 패킷 직렬화 공부 과정의 첫 삽을 뜨게 됐다. Protobuf를 사용하면 어느 정도는 그냥 넘어갈 수도 있겠으나, 동작 원리와 그 장단점에 대해 아는 것이 중요하다는 그 말이 가슴에 남는다. 결국 알아야 더 잘 사용할 수 있는 게 아닐까. 1. 본격적으로 들어가기 전에 기존에 구현한 버퍼를 사용하는 방법에 대해 돌아보자. SendBufferRef sendBuffer = GSendBufferManager->Open(4096); BYTE* buffer = sendBuffer->Buffer(); ((PacketHeader*)buffer)->size = (sizeof(sendData) + sizeof(PacketHead..
[C#] PingPlugin
·
Study/C++ & C#
평화로운 FF14 라이프를 구가하던 중... PingPlugin이라는 핑을 표시해 주는 플러그인이 제대로 동작하지 않는다는 소식을 들었다. 난 글로벌 서버가 메인이기 때문에 옆동네 이슈엔 별 관심이 없지만... 지인이 필요하다고 하니 한번 들여다보기로 했다. 1. 상황 파악 결정했으면 뭐가 안되는지 파악해야 한다. IP는 잡아오는데 핑이 계속 0이라고 하더라. 그래서 다른 방법들을 다 테스트 해 봤는데 되는 게 딱 하나 있었다. 패킷이 오고 가는걸로 핑을 재는 기능이었다. 여기서 마나데센까지의 핑이 40초반대이다. 핑 측정도 제대로 안되고 쓰지 않으니만 못하다. 그럼 다른 측정 방식은 왜 동작하지 않는지 일단 자체적으로 핑을 때려보도록 하자. ICMP 프로토콜을 완전히 블락한다. 흠... 일단 이거는 막..
[C++] Packet Session
·
Study/C++ & C#
지금까진 단순히 "Hello World"라는 문자열을 주고받기만 했다. 이대로라면 통신은 되지만 서로 원하는 데이터를 확실하게 주고 받지는 못할 것이다. 클라이언트에서 특정 처리에 대한 요청을 보내는데 TCP 특성 상, 그 내용이 완전한 형태로 한 번에 서버에 도착한다는 보장이 없다. 따로 와버린 데이터에 대해 서버가 그 요청에 맞는 처리를 할 수 없는 것은 당연하다. 따라서 헤더를 가지는 「패킷」을 활용하여 통신되는 데이터를 구분할 수 있게 할 것이다. 1. 클래스 작성 패킷을 사용한다고 해서 기존의 통신 방식과 완전히 다른 것을 사용하는 것은 아니다. 「Hello Wolrd」라는 데이터 앞에 이 데이터의 크기는 얼마고, 이 패킷은 뭘 하는 패킷이다라는 것을 알려주는 부분을 추가할 뿐이다. 웹 통신에서..
[C++] SendBuffer Pooling
·
Study/C++ & C#
이전엔 단순히 버퍼를 필요할 때 만들어 사용하는 형태였다면, 이번엔 풀링을 통해 미리 버퍼들을 풀링해 돌려쓰는 방식으로 돌아가게 할 것이다. 1. SendBuffer 클래스 수정 풀링을 사용할 것이기 때문에 아래의 클래스들을 새로 작성할 것이다. SendBufferChunk - SendBuffer들의 덩어리(Chunk)이다. 버퍼들을 Array형태로 갖고 있을 것이다. SendBufferManager - SendBufferChunk들을 관리할 매니저 클래스이다. 먼저 SendBufferManager부터 만들어가 보자. class SendBufferManager { public: // 큰 버퍼에서 내가 일정 부분만큼 사용하기 위해 연다는 느낌 SendBufferRefOpen(uint32 size); pri..