[C++] JobQueue (3 / 3)
·
Study/C++ & C#
지금까지의 코드에선 하나의 스레드에 일감이 몰리는 상황이 발생할 수 있었다. 목표는 이 일감을 최대한 분배해 한 스레드만 괴롭히는 현상을 해소하는 것이다. 여기선 JobQueue를 보관할 GlobalQueue를 만들어 이를 뿌리는 식으로 만들어 본다. 1. 클래스 작성 기본적인 기능만 수행할 것이기 때문에 복잡한 일은 없다. // GlobalQueue.cpp #pragma once class GlobalQueue { public: GlobalQueue(); ~GlobalQueue(); voidPush(JobQueueRef jobQueue); JobQueueRefPop(); private: LockQueue _jobQueues; }; // GlobalQueue.h #include "pch.h" #inclu..
[C++] JobQueue (1 / 3)
·
Study/C++ & C#
멀티 스레드 환경이기 때문에 JobQueue의 중요성이 두드러진다. 이에 대해 알아보자. 1. JobQueue가 왜 필요한데? 스레드끼리의 경합을 예방해 더 효율적인 처리를 가능케 하기 위함이다. 밥집을 갔다고 생각해 보자. 손님들이 주문서를 작성하는 것이 아닌, 바로 주방에 와서 이것저것 주문한다. 주방엔 주방장 단 한 명. 주문이 오는 대로 주방장은 만들기 시작하고, 주방장은 한 명뿐이기 때문에 주방장이 내 주문을 만들게 하기 위한 경합이 생긴다. 먼저 주문하려고 했어도 경합에 실패에 순서가 밀릴 수도 있다. 여러 개의 음식이 갖춰져야 하는 상황이라고 했을 때 경합에 계속 실패한다면 문제가 된다. 손님들은 주방 앞에서 내 주문이 완료될 때까지 기다려야 하니 답답하다. 손님 나름대로 다른 일을 하지 못..
[C++/C#] C# 채팅 클라이언트 간보기
·
Study/C++ & C#
왜 간보기냐면 C#으로 모델을 구현하고 패킷 핸들링을 진행하지 않기 때문. 입력을 받고 출력하기만 하는 창구 역할만 수행한다. 1. 구현 방법 이미 이전에 파이썬을 활용해 패킷 자동화까지 해 놓았다. 아무래도 C#에서까지 같은 작업을 하기보단 있는 걸 끌어오는 게 편할 것 같았다. 그래서 기존의 DummyClient를 DLL로 만들어서 P/Invoke를 활용하기로 했다. 따라서 아래의 기능들이 필요하게 된다. 접속부터 패킷 핸들링 까지 할 메인 스레드 상호 간 데이터를 전달하기 위한 송수신 데이터용 Queue 데이터를 주고받기 위한 C++ 함수들 클라이언트에서 출력과 입력을 받을 각각의 스레드 2. 메인 스레드 거창할 건 없고 그냥 기존 코드의 재활용이다. extern "C" { __declspec(dl..
[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++] Packet Session
·
Study/C++ & C#
지금까진 단순히 "Hello World"라는 문자열을 주고받기만 했다. 이대로라면 통신은 되지만 서로 원하는 데이터를 확실하게 주고 받지는 못할 것이다. 클라이언트에서 특정 처리에 대한 요청을 보내는데 TCP 특성 상, 그 내용이 완전한 형태로 한 번에 서버에 도착한다는 보장이 없다. 따로 와버린 데이터에 대해 서버가 그 요청에 맞는 처리를 할 수 없는 것은 당연하다. 따라서 헤더를 가지는 「패킷」을 활용하여 통신되는 데이터를 구분할 수 있게 할 것이다. 1. 클래스 작성 패킷을 사용한다고 해서 기존의 통신 방식과 완전히 다른 것을 사용하는 것은 아니다. 「Hello Wolrd」라는 데이터 앞에 이 데이터의 크기는 얼마고, 이 패킷은 뭘 하는 패킷이다라는 것을 알려주는 부분을 추가할 뿐이다. 웹 통신에서..