월 66,000원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
char8_t 관련 protobuf 질문
google Protobuf에서 한글을 보낼때는 utf8 형식으로 보내야하는 걸로 알고 있습니다. 그래서 u8을 앞에 붙여서 set_name()에 인자를 넣은거구요. 근데 C++언어 표준을 latest 로 해놓고 하면 google protobuf 쪽에서 char8_t 를 지원을 안해주어 컴파일에서 걸렸습니다..C++ latest 로 지정하고 u8을 하면 문자열이 const char8_t 로 변환되더라구요. 이전 C++ 17 이전으로는 u8을 해도 const char로 변환되었습니다. 그래서 기존에는 컴파일타임에 걸리지 않고 실행이 된것 같습니다.그래서이렇게 u8을 쓰지 않고 converter 를 통해 utf8 로 변환 후 패킷을 보냈습니다.이렇게 하니까 한글이 정상 출력이 되는 걸 확인했습니다..이런 방식도 나쁘지 않은 방식인가요...?제가 의심을 하는 이유는 codecvt_utf이 deprecated 된 것인데 경고를 무시하는 코드를 넣고 실행을 돌리기 때문입니다.C++ latest 에서 사용하기 위해서는 제가 생각한 최선의 방법이었습니다.좋은 방법이 있을까요
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
World Update Packet 처리
안녕하세요 강의 잘 보고 있습니다!!다름이 아니라 IOCP를 이용하여 언리얼 클라이언트와 연동을 하고 있는데 패킷을 보내는데 의문이 들어서 이렇게 질문을 남깁니다. 클라이언트 코드에서는 타이머를 이용하여 초당 60개의 패킷을 서버로 전송합니다.(서버에 접속이 성공적인 경우에 한해서) 그후 서버에서는 작업자스레드에서 모든 입출력을 처리를 하게 되는데, 만약 클라이언트 수가 많아지면 그만큼 서버에서 모든 클라이언트의 초당 패킷을 처리하게 되므로 과부하가 심해질 것으로 예상이 됩니다. 이에 따라 PQCS함수를 이용하여 저가 자체적으로 UPDATE이벤트를 넣어주어 처리를 하려고 했는데 생각한것처럼 잘 되지가 않아서요.. 아니면 그냥 서버에서 UPDATE쓰레드를 따로 구분지어서 클라이언트에게 브로드캐스트를 하는것이 방법일까요? 어떤 것이 좋을지 감이 안잡혀서 이렇게 질문남깁니다!!
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Variadic 함수 인자 포워딩 관련
수업의 JobSerialize::PushJob() 함수에서, template<typename T, typename Ret, typename.. Args>void PushJob(Ret(T::*memFunc)(Args...), Args... args){.... std::forward<Args>(args...)} 이 부분에서PushJob() 인자 중 Args&&... 가 아닌 Args... 로 &&을 생략해도 포워딩이 정상적으로 진행이 되는 건지 궁금합니다. 구글링을 해 보니 전부 Args&&... 형태로 쓰는 것으로 보여서요. 가변 템플릿 문법은 언제나 굉장히 헷갈리네요.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
콜백 방식에 비해 이벤트 방식의 단점?이 와닿지 않습니다
콜백 방식에 비해 이벤트 방식의 단점?이 와닿지 않아서 질문 남깁니다. 아마 제가 대규모 유저를 받는 환경의 코드를 아직 보지 못해서 그런 것 같아서 와닿지 않은것 같습니다. 설명해주신 내용은 클라 소켓 하나당 이벤트 하나를 대응시켜야 하는데 64개까지 제한이고, 여러명을 받는 서버의 코드는 코드가 간단하지 않다는 점을 단점으로 꼽으셨는데 와닿지 않습니다.정말 이벤트를 64개 넘게 관찰해야 하는 상황이 있나요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
event관련 질문입니다.
저렇게 SetEvent를 주석을 달고 했을때 무한 대기상태로 들어가는건 이해가 됬습니다. 저상태에선 브레이크 포인트를 잡는다던가, 디버그 행동을 할 수가 없나요?? 저는 현재 WaitForSingleobject가 쓰레드 함수가 끝날때까지 대기 하는것으로 이해하고 있습니다. 쓰레드 함수가 정상적으로 끝나는게 아닌, 외부 함수에 의해서 강제강료 했을때 무한대기 하는 상태가 발생하는데, SetEvent를 호출하지않고 강제종료되는 경우를 고려할수있을까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
google Protobuf 관련 메모리 릭
CrtDumpMemoryLeaks(); 함수 호출을 통해 메모리 릭을 검사했는데 강사님의 코드에서는 다 잘 지우는 것 같아서 강사님 코드에서의 릭은 아닌것 같습니다.. 강사님 코드에서 객체 생성을 다 막고 디버깅해도 똑같은 메모리 릭이 남았습니다.. google protobuf 에서의 릭인 것 같은데.. pb.h pb.cc 는 건들지 못하니 고칠 방법도 없고 해서 이렇게 질문 올립니다. 저 메모리 릭을 해결하는 방법이 있을 까요..?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Win32API 클라이언트 연동
강의에서는 서버에서 정해진 데이터(id, hp, 공격력)를클라쪽으로 broadCast 하고,클라에서는 Recv만 하고 있는데, 클라쪽에서도 Send하고서버에서 Recv하는 echo방식으로는어떻게 수정해봐야할까요..? ㅠ 목적은 Win32APi로 만든 클라이언트 2~3개정도 켜서 PacketHandler까지 구현된 Server와 붙혀서 이동동기화 부터 시도하고 있습니다그래서 클라이언트 1개에서 만약 이동했다면 그 행동이서버랑 다른 클라이언트에도 똑같이 보이게하고 싶습니다ClientPacketHandler에 ServerPacketHandler의 Make_S_TEST 함수를 복붙하고GameServer의 방법과 같이 BroadCast를 해야할지 아니면 Send함수를 따로 구현해야 할지 방향을 못잡겠습니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
RegisterRecv() 함수에서
WSABUF wsaBuf; ::WSARecv(_socket, &wsabuf, ...);위 코드에서 WSABUF 타입 객체를 스택에 생성에서 WSARecv() 함수에 넘기면 이 함수가 바로 완료되지 않고, 나중에 완료 통지로 받는다면 스택에 생성된 WSABUF는 그전에 해제되서 잘못된 메모리에 쓰게 되는 게 아닌가요?또 이런 api들을 호출할 때 넘길 파라미터를 스택에 생성할 지 new 로 힙에 생성할 지 기준은 어떻게 정하시는지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
클라이언트에 ServerCore를 복사 시, #include 안될 때
포트폴리오 작업하고 있는데, 클라이언트를 PacketHandler까지 작업 완료된 서버랑 연동해보려고 합니다~ ClientServiceRef service = MakeShared<ClientService>(NetAddress(L"127.0.0.1", 7777),MakeShared<IocpCore>(),MakeShared<ServerSession>, // TODO : SessionManager 등1); 클라이언트쪽에서 위와 같은 코드로 서버와 연결하기 위해 ServerCore 라이브러리를 통쨰로 클라이언트쪽으로 가져와야 하는데... 비쥬얼 스튜디오 2022에서파일 --> 추가 --> 기존 프로젝트 메뉴 이 기능으로 ServerCore 프로젝트를클라이언트 솔루션에 복사 하고,파일탐색기에서도 ServerCore 폴더를 클라이언트쪽에 통쨰로 옮겼는데도#include가 안되고 있는데, 방법을 알 수 있을까요?? 클라이언트 솔루션에 ServerCore 프로젝트 추가완료 GameProjcet .cpp소스에서 ServerCore 쪽 파일들 인클루드 시도했으나 에러발생
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
LNK1104 'Debug\ServerCore.lib' 파일을 열 수 없습니다. 에러 질문
안녕하세요! Lock-Based Stack / Queue 강의부터 수업 자료를 다운로드 받아서 실행 시킬 경우 위와 같은 에러가 발생합니다. 라이브러리 파일을 열 수 없다고 뜨는데, 이에 대한 원인을 찾아 보고 있으나 진전이 없어서 무엇이 문제일까 여쭤봅니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Select 모델을 사용해야 하는 이유
강의를 수강하던중 Select 모델과 (Non)blocking의 차이점에 궁금증이 생겨 질문을 남기게 되었습니다. Select를 사용하기전 Blocking, Non-blocking 방식에서도 해당 소켓의 정상/비정상 상태를 확인하여 패킷을 전송하는 것으로 이해하였습니다. 그중 Non-blocking은 명칭적으로는 정상/비정상에 큰 신경을 쓰지 않지만 소켓의 상태가 정상/비정상인지 확인하는 과정을 거치기에 자원 손실이 일어나는 것으로 이해됐습니다. 이런 단점을 해결하기 위해 Select 모델을 이용해 send, write에 소켓을 저장해 해당 소켓이 정상인지, send, recv 중 어떤 소켓을 진행해야 할지, 준비되었는지 판단하는 과정이 Blocking과 Non-blocking에서의 상태 파악 과정과 비슷하다는 생각이 들어 Select 모델을 사용하는게 별 다른 이점이 없지 않나? 라는 생각이 들어 질문을 남기게 되었습니다.
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
SocketUtils::SetTcpNoDelay 부분 오타
bool SocketUtils::SetTcpNoDelay(SOCKET socket, bool flag) { return SetSockOpt(socket, IPPROTO_TCP, TCP_NODELAY, flag); }로 코드를 고쳐주어야 할 것 같습니다. (SOL_SOCKET -> IPPROTO_TCPSOL_SOCKET, TCP_NODELAY로 인자를 넣어주면 SO_DEBUG 옵션을 대신 설정해주게 됩니다. 현재 기준으로 마지막 코드까지 오타가 수정되어 있지 않으니 혹시 실제로 서버를 사용하실 분들은 해당 코드를 수정하여 사용하시는걸 권장드립니다.
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Conditional Variable 과 Event에 대해 이해하고 싶습니다.
제가 이해한것이 맞는지 확인하고 싶어 질문을 남기게 되었습니다. Event는 Signal, Non-Signal 상태를 WaitForSingleObject(handle, INFINITE)를 통해 대기합니다.여기서 INFINITE로 무한정 대기를 통해 불필요한 컨텍스트 스위치가 일어나지 않게 됩니다.하지만 그만큼 자원(메모리? CPU? )의 손해가 일어나기에 생겨난 것이 Conditional Variable입니다. Conditional Variable cv.notify_one();를 통해 대기하고 있던 Thread를 실행합니다. Conditional Variable는 메모리에 Thread를 Wait 시키지 않고 대기 시키다가 cv.notify_one();를 통해 실행하는 것이고 Event는 Thread를 메모리에 WaitForSingleObject(handle, INFINITE)를 통해 대기시켰다가 SetEvent(handle);를 통해 실행시킨 점이 차이라고 이해하면 될지 여쭙고 싶습니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
buffsOffset을 사용하는 이유가 궁금합니다.
안녕하세요 지난 강의 '패킷직렬화 #1' 부터 현재강의에서 buffsOffset을 사용하는데 이 변수가 존재해야 하는 이유를 모르겠습니다.sizeof(PKT_S_TEST)를 이용하면 되는게 아닌지 자꾸 의문이 들어서요.sizeof(PKT_S_TEST)를 이용해서는 안되는 경우가 있어서 buffsOffset을 사용하는 걸까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ObjectPool.h Push에는 괄호를 안쓴 이유가 무엇일까요
ObjectPool.h에서 게임서버쪽에서 MakeShared를 사용할때도 메모리 풀이 적용되게해주는 함수인데여기서 Push는 왜 괄호를 안쓴걸까요 ?? static shared_ptr<Type> MakeShared() { shared_ptr<Type> ptr = { Pop(), Push}; return ptr; } GameServer.cpp에서 이미 아래와 같이 인자를 전달해서 그런걸까요..??왜 이렇게 되는지 궁금합니다..ObjectPool<Knight>::Push(knights[i]);
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
UniqueLock과 Lock의 차이점이 궁금합니다.
uniquelock은 lock_guard와 달리 std::unique_lock<std::mutex> uniqueLock(m, std::defer_lock);를 통해 명시해놓고 자신이 원하는 순간에 uniqueLock.lock 을 할 수 있다고 이해하였습니다. 일반적인 Lock과의 차이점은 자신이 원하는 순간에 lock을 거는 것은 똑같지만lock_guard와 같이 unlock과 같이 명시를 해주지 않더라도 일정 부분이 끝나게 되면 자동으로 unlock이되는 것이라고 이해해도 괜찮을까요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ThreadManager::Join 관련 질문입니다.
void ThreadManager::Join() { LockGuard guard(_lock); for (thread& t : _threads) { if (t.joinable()) t.join(); } _threads.clear(); }for문 후에 _threads에 들어와서 실제로 join 되지 않고 clear되는 thread가 존재 할 가능성이 있어 보입니다. 그래서 Lock이 필요하다는 생각이 듭니다. 근데 강의 코드에서는 없이 사용하셔서 Lock이 없어도 괜찮은지 질문드립니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
send 함수 질문이 있습니다
send를 사용할 때 블로킹 모드는 모든 데이터를 다 보내고 논블로킹은 일부만 보낼 수가 있다고 하셨는데 이 보낸다는 게 send를 사용한 사용자 커널에 있는 송신 버퍼에 보낸다는 건가요? 아니면 받는 사용자 커널에 있는 수신 버퍼에 보낸다는 건가요?그리고 논블로킹 모드에서 데이터를 일부만 보낼 수가 있으면 UDP에서는 데이터 경계의 대한 개념이 있으니까 논블로킹을 사용할 수 없는 건가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
LEndTickCount를 중복검사 하는 이유가 궁금합니다.
요즘에도 답 달아주시는지 궁금하네요.ㅎㅎDoGlobalQueueWork()랑 JobQueue::Execute()에서 LEndTickCount를 검사하는데 굳이 DoGlobalQueueWork()에서도 검사해야 할 특별한 이유가 있을까요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
본 강의 코드에서 Event와 CV간의 논리적 순서 차이
Event는 커널 레벨에서 다른 쓰레드와 통신하기 위해 사용하는 것이고 (이런 점에서 IPC와 유사하다고 생각됩니다. 하지만 프로세스와 달리 쓰레드는 메모리를 공유하므로 더 효율적이겠구요...) Condition Variable은 유저 레벨에서 직접 구현하는 것이라 생각하면 굳이 OS API 및 커널의 도움을 받지 않고 조건을 체크한다는 것으로 이해하였습니다.CV에서...일단 락 받아조건 맞아? 조건 안 맞으면 락 풀어. 다음 기회에...다른 thread에서 신호 줄때까지 blocked위 처럼 설명하신 것 같은데, 이해가 가지 않는 부분이 몇 군데 있어 질문드립니다.Q1. unique_lock<mutex> lock(m)은 생성자에서 이미 락을 잡았을텐데, 왜 cv.wait()에서 "1) Lock을 잡고" 부분에서 다시 락을 잡는건지 궁금합니다. 100% 락을 잡았다는 보장이 없는 것인가요?? 생성자에서 락을 잡지 못하면 어차피 다음 코드 실행이 안되지 않나요? (혹은 조건을 불만족했을때 cv.wait()에 대한 루프를 돌아야 하기 때문에 락을 다시 잡는 것인가요?)Q2. 왜 예제 코드에서는 Event 방식보다 CV 방식이 효율적이라고 하신건지 궁금합니다.결국 CV방식에서도 Blocking된 쓰레드를 깨우려면 커널의 도움을 받아야 하는 것 아닌가요?로직 상으로도 둘 다 바쁜 대기가 존재하지 않고 같은 순서로 동작하는 것 같은데 코드의 길이가 줄어서 효율적이라고 하신 건가요?