no image
서버 작업 복습
작업한 서버에서 얼마만큼의 동접을 받을 수 있느냐 라는 질문을 받았을 때 대답할 수 있어야 한다! 스트레스 테스트 필수! 현재 작업한 모델은 IOCP 모델로 성능이 괜찮고 효율이 좋게 나오는 모델이다. 이외에도 select 모델 같은 무식?한 방식으로 테스트 해도 3~4천명은 그냥 나온다고 한다. MMO 서버에서 성능을 잡아먹는 3대장이 있다. 1. cpu 부담 2. 네트워크 3. DB(데이터 양이 진짜 많을 때) 이런 부분까지 고려해서 대답할 수 있어야한다. 프로토콜 관리 작업한 서버 프로젝트에서는 protobuf 와 파이썬의 jinja2 템플릿 엔진?을 사용해 자동화시켜서 관리하였다. protobuf로 설계한 패킷을 파이썬 코드가 읽어서 자동으로 패킷에 관련된 코드를 만들어준 다. 서버 개론 -Thr..
2024.03.29
no image
JobTimer
서버에서는 클라이언트 처럼 무한대로 틱을 이용하여 무언가를 체크하거나 실행하는 일이 잘 없다. 그러니 정해진 시간뒤에 일어나야 하는 이벤트 같은 경우를 처리하기 위해 JobTimer를 만들어 주자. 이 JobTimer는 중앙 통제를 이용한 예약 시스템으로 중앙에서 모든 일감을 가지고 있다가 빠르게 체크하여 뿌려주는 방식이다. JobTimer.h #pragma once struct JobData { JobData(weak_ptr owner, JobRef job) :owner(owner), job(job) { } weak_ptr owner; JobRef job; }; struct TimerItem { bool operator < (const TimerItem& other)const { return execu..
2024.01.19
JobQueue(5)
CoreTLS 코드 수정 //추가 extern thread_local class JobQueue* LCurrentJobQueue; extern thread_local uint64 LEndTickCount; LCurrentJobQueue : 내가 실행하고 있는 JobQueue를 확인하기 위한 JobQueue 포인터 추가 LEndTickCount : 틱이 완료되는 시간 전에 말했듯이 하나의 스레드에 일감이 몰리게 될 수도 있다. 이를 해결하는 가장 간단한 방법은 스레드가 JobQueue를 호출하고 있는지 아닌지를 판별하여 이미 호출하고 있다면 처음으로 job을 넣었다고 하더라도 실행시키지 않고 다른 스레드로 넘기게 될 것이다. JobQueue.cpp 수정 void JobQueue::Push(JobRef&& ..
2024.01.17
JobQueue(4)
기존에 우리가 Job을 push하고 pop할 때 GRoom을 만들어서 Flush해주고 있었다. 근데 심리스 mmo 같은 경우에는 모든 액터에 JobQueue를 넣어주는 경우가 많다고 한다. 하지만 그렇게 될 경우에 while문으로 flush 하는 부분과 객체가 많아지게 되면서 스레드 끼리 일을 분배해서 처리하기 까다로워 진다. 이런 부분들을 기존의 Session::Send(...)함수처럼 먼저 일감을 넣은 쓰레드가 실행하도록 개선해보도록 하자. JobQueue.h ( JobSerializer.h 에서 이름 바꿈.) #pragma once #include "Job.h" #include "LockQueue.h" /*================== * *JobQueue * ==================*..
2024.01.05
no image
JobQueue(3)
c++ 11로 넘어오면서 굉장히 강력한 기능이 생겼다. 바로 람다식과 functional을 조합하는 것이다. 이 기능을 사용하여 기존의 복잡한 과정을 걸쳐 생성했던 Job을 간단하게 생성할 수 있도록 코드를 수정해 볼것이다. 일반적인 함수포인터 같은 경우에는 인자를 저장할 공간이 없기 때문에 인자를 저장할 공간을 만들어서 거기에 저장해주고 있었다. (전에 사용하던 Job 클래스에서 만든 functor안에 튜플로 함수 인자를 저장해주고 사용할 때 불러옴.) 하지만 람다에선 그런 과정없이 함수를 호출할 수 있다. 이런 장점이 있지만 사용할 때 주의해야 할 점 또한 있다. 1. 참조로 캡쳐할 경우. std::function func = [&player]() { GRoom->Enter(player); }; 이런..
2024.01.03
no image
JobQueue (2)
전에 작업했던 원시적인 방법에서 코드를 수정하여 공용 클래스를 만들어서 일감(Job)들을 관리하도록 해보자. 그러기 위해 아래와 같이 템플릿 함수자를 만들어 주자. template class FuncJob { //FuncType은 반환값은 Ret이고 인자로는 Args 여러개를 받아준다. using FuncType = Ret(*)(Args...); public: FuncJob(FuncType func, Args... args) :_func(func), _tuple(args...) { } Ret Execute() { std::apply(_func, _tuple); //C++ 17 } private: FuncType _func; //일종의 콜백함수 std::tuple _tuple; }; 크게 복잡한거 없는 간..
2023.12.29
no image
Job Queue (1)
전에 채팅 프로그램을 정리하는 글에서도 말했듯이 지금은 모든 함수에 락을 걸어놓는 원시적인 방법으로 구현해놓았다. 작은 규모의 프로젝트면 큰 문제가 없지만 큰 규모의 프로젝트라면 스레드간의 경합이 심해지게 되면서 큰 문제가 발생한다. 위와 같이 구현하게 될 경우, 만약 다수의 클라이언트가 우연히 같은 함수(ex : Broadcasting)를 처리하려고 시도하게되면, 먼저 락을 잡고 처리중인 하나의 스레드가 일을 마칠동안 다른 스레드는 대기하면서 자원만 낭비할 것이고, 심지어 스핀락으로 구현했기 때문에 계속 루프를 돌며 cpu 자원만 고갈하게 될 것이다. 이를 해결하기 위해 우리는 커맨드 패턴을 사용한 Job 방식으로 수정할 것이다. 커맨드 패턴 행위 패턴 이벤트가 발생했을 때 실행될 기능이 다양하면서도 ..
2023.10.03
no image
에코 채팅 프로그램
이번에는 이 때까지 작업한 내용들로 간단하게 Hellow World를 출력하는 에코 채팅 프로그램을 만들어보자. 우선 기존에 테스트 용도로 만들었던 프로토 파일들을 위와 같이 수정해주고 빌드를 하자. 그러면 우리가 기존의 만들었던 자동화 프로그램에 의해 새로운 코드들이 생길 것이다. 새로 생긴 코드를 작업하기 전에 간단하게 방과 플레이어 정보를 저장할 클래스를 새로 생성해주자. 이제 새로 생긴 패킷관련 코드들을 작업해보자. 어렵게 생각 할 것 없이 클라이언트와 서버 모두 대칭적으로 구현해주면 된다. 서버 bool Handle_C_LOGIN(PacketSessionRef& session, Protocol::C_LOGIN& pkt) { GameSessionRef GameSession = static_poin..
2023.10.02
no image
ProtoBuf
protoc : 프로토 버프 컴파일러 프로토 파일을 C++이나 C#이나 온갖 언어에 맞는 클래스로 만들어 줌. Protocol.proto 테스트용 파일 생성. 기존에 XML로 작성했던 패킷 구조를 프로토 버프로 작성. 프로토 파일이 변환 되면서 나중에 클래스나 구조체로 변경 됨. 이제 컴파일러를 통해 생성한 프로토 파일을 C++로 변환시켜주면 된다. Protobuf 사이트에 있는 명령어를 복사해와서 배치 파일 생성. 배치 파일 실행 하면 아래와 같은 오류가 발생 하는데 이는, protobuf에는 uint32까지만 있기 때문이다. https://protobuf.dev/programming-guides/proto3/#scalar Language Guide (proto 3) This topic covers h..
2023.06.26