월 66,000원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
SpinLock 구현 과정에 대해서 질문이 있습니다.
SpinLock 에 사용되는 특의 함수,atomic 키워드와compare_exchange_strong() 메소드를 쓰면서 구현을 하는 과정에 대해서 들었는데,의문점이void Add(), Sud() 메소드에순서상의 lock_guard() 를 먼저 실행하면 되지 않을까 생각합니다.thread1,thread2두 개의 쓰레드가 하나의 locked 부울 데이터를 공유한 상태에서 동시에 lock_guard() 를 할 수 있는 경우에서 locked 부울을 동시 접근하는 경우도 있겟지만,=> 이러면 deadlock 이 발생하겠죠.같은 말로,thread t1(Add);thread t2(Add);같은 경우도 위에 deadlock 발생하는 같은 이치라고 보시면 될꺼 같습니다.결국에는 locked 부울 데이터를 공통적으로 사용한다는 부분에서 생기는 문제니까요.즉, thread 1 또는 thread 2 가 동시적으로 접근하지 않는 이상 deadlock 은 발생하지는 않을 것이며,add 메소드에서 lock_guard() 를 했기에, 모든 작업을 다 끝내고 그 다음 add() 메소드를 실행하지 않을까 하고 생각합니다.하지만 main 에서 Add(), Sub() 를 순차적으로 실행했기에 Add() 에 먼저 thread1, thread2 가 동시에 수행을 한다해도 결국에는 Add() 메소드에서 lock_guard 를 둘 중 하나가 먼저 수행하기 때문에 Add() 메소드를 먼저 접하는 thread 가 수행을 하고,그 뒤의 Sub() 메소드 또한 실행을 하지만,이 또한 thread 1 또는 thread 2 둘 중 하나가 lock_guard() 를 하고 있는 상태이기 때문에 다른 스레드가 _locked 부울에 접근을 하지 못하는 이유로 deadlock 이 발생하지 않고 원하는 값이 출력되지 않을까 생각했고, 실제로도 0 값이 나오기는 했습니다.좀 더 정확하게는,멀티스레드가 순차적으로 수행하지 않고 동시 다발적으로 실행이 된다면 종류는 아마,1. A thread Add() 실행B thread Sub() 실행 2. B thread Sub() 실행A thread Add() 실행3. A, B thread Add(), Sub() 동시 실행같은 경우의 수가 더 있을 수도 있지만 현재는 여기 까지 밖에 볼 수 없었습니다.만약 main() 함수에서 3번 경우에서 두 메소드에서 동시 다발적으로 처리를 수행한다면 deadlock 이 테스트를 하면서 운이 좋게 안 뜬걸로 볼 수있지만,순차적으로 Add() -> Sub() 식이라면, 즉 1번 경우라면 SpinLock 을 처음 방식처럼 구현하는 상태에서,lock_guard() 메소드를 순서를 바꿔서 처리하는 방법도 옳은 방법으로도 되는지 알고 싶습니다.int32 sum;class SpinLock{public:void lock(){ while (_locked){}_locked = true;}void unlock(){_locked = false;}private:bool _locked = false;};void Add(){lock_guard<SpinLock> guard(spinLock);for (int32 i = 0; i < 10'000; ++i){sum++;}}void Sub(){lock_guard<SpinLock> guard(spinLock);for (int32 i = 0; i < 10'000; ++i){sum--;}}void main(){thread t1(Add);thread t2(Sub);t1.join();t2.join();cout << sum << endl;}.. 생략
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
MMORPG 초당 패킷에 관하여 궁금한점
안녕하세요.선생님 MMROPG 초당 패킷에 관하여 궁금한 점이 있습니다.지금 현재 Unity 클라이언트를 사용하여, 플레이어 움직임을 동기화 작업을 하고 있습니다.위메x드의 신규 게임인 나이트크로우의 플레이어 움직임을 모방하여 구현하고 있습니다.(나이트크로우는 카메라가 바라보는 방향으로 플레이어의 방향이 결정됩니다.)위,위 오른쪽, 오른쪽, 아래 오른쪽, 아래,아래 왼쪽,왼쪽,위 왼쪽,이렇게 8방향으로 움직입니다. 1초에 패킷이 얼마나 날아가는지 로그를 찍어 보았더니일반 MMORPG 게임을 하는 것처럼 움직이면 초당 평균 6개 정도 날아갑니다.하지만 인위적으로 키보드와 카메라를 엄청 움직이면 초당 최대 40번 까지 패킷이 날아갑니다. 제가 실무 경험은 없어도 MMORPG가 움직임만으로 초당 40번의 패킷을 쏘는건 문제가 있어 보입니다.그래서 나이트크로우에서는 어떻게 처리를 했나 확인하려고 들어가서 인위적으로 마구마구 움직여보니깐제 유니티 화면이랑 똑같이 마구마구 움직입니다.(다른 플레이어가 봤을 때 어떻게 움직이는지는 잘 모르겠습니다.)이러한 상황이고 패킷을 줄이는 해결방안을 모색중입니다. Dead Reckoning 방법을 써서 어느정도 패킷을 줄였는데도 짧은 거리를 마구잡이로 방향을 바꿔버리면서 이동하면 패킷이 그대로 날라가 버리게 되어서 문제입니다... <질문 요약>MMORPG 1초당 패킷 적정 수현업에서는 플레이어가 인위적으로 (앞으로 갔다 뗐다 빠르게 반복) 움직이는 걸 어떻게 처리하는지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
CoreGlobal
CoreGlobal을 생성한 적이 없는데 어떻게 모든 전역변수들이 초기화 되는 건가요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
서버 연동 질문드립니다
벌써 루키스님 강의를 보기 시작한지 2년이 넘었습니다.항상 좋은 강의 감사드립니다 특히 요즘 다이렉트 강의보면서 혼자 공부할 때는 많이 힘들었는데 엔진 구조 개발 부분에서 많이 얻어가고 있습니다.이 강의를 공개하신 시점도 벌써 2년이 지나게 되었는데 혹시 언리얼과 게임서버 연동 하실 때 이 서버를 그대로 사용 하실 것 인지 아니면 다른 방식으로 업그레이드 후 서버 개발 후 연동하실지가 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
내장 SQL Server
SQL Server 2022에서는 SQL Server Native Client 드라이버가 제거된 것 같습니다. 이 경우에는 ODBC Driver 17 for SQL Server 드라이버를 활용하면 되나요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
수업자료 다운로드 후 빌드 오류
첨부파일을 다운받아 그대로 빌드를 실행했는데, 다음의 부분에서 에러가 생깁니다.#if 3017001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. #endif이상한 점이 protoc 3.17.1 버전으로 생성한 Enum.pb.h인데 PROTOBUF_MIN_PROTOC_VERSION의 값이 3021000으로 뜹니다. 혹시 Visual studio 2022를 사용해서 ide때문에 에러가 생기는 것일까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
의사코드 질문입니다.
while 루프 내부에서 expected = false 를 굳이 왜 해야하는 질문이 들었는데요.의사코드를 보면 else 구문에서 expected = locked에 때문에 한다고 말씀해주셨는데결국 if문에서 _locked=true일 때 조건을 만족하는 경우가 생겨서 그런건가요? false로 조건을 통과해야되는 데 말이죠. (잠겼는데 통과하는 경우가 발생) 그렇다면 의사코드에서 else 구문에서 expected = _locked을 왜하는지 의문이 드는데, "그냥 칩회사에서 그렇게 구현했다." 라고 받아들이면 되는건가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
IOCP 관련 질문이 있습니다.
이제 개발을 할때 WSASend함수를 통해 Scatter-Gether 방식으로 전달을 한다고 하면 내부적으로는 해당 데이터들이 하나의 Sendbuffe에 담겨서 가는지가 궁금합니다.WSASend에 요청한 데이터가 너무 커서 2번이상의 걸처 나눠서 전송이 된다면, 모든 데이터가 전송이 완료되어야지만 IOCP GQCS에서 완료되었다는 사실을 알 수 있는지 궁금합니다. 정리)1. Scatter-Gether를 통해서 여러 데이터를 보내면 내부적으로 1개의 Send Buffer에 담아서 보내지는지2.WSASend 호출 -> 데이터가 너무 커서 2개로 짤림이때 1개의 데이터를 전송 완료 후 GQCS OR2개의 데이터를 전부 전송 완료 후 GQCS에 등록 이 되는지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
DisconnectEx
해당함수를 사용하면 기존에 생성했던 Socket을 다시 만들필요 없이 재사용할 수 있다라고 설명하셨는데, 해당 코드를 보면 Disconnect가 될 시 Service에서 Session을제거하기 때문에 해당 Session은 메모리에서 해제가 되는것으로 알고 있습니다. 그럼 다시 CreateSocket함수를 통해서 socket이 생성되면 사실 의미가 없는게 아닌가 궁금합니다. 그냥 SocketPool을 만들어서 제가될떄 넣고, 생성될때 꺼내쓰는게 효율적일 것 같은데 혹시 어떻게 생각하시는지 궁금합니다.
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
게임 설명란의 포폴이요
혹시 강의 설명란에 나와있는 mmorpg 3d 게임 포폴을 완성하려면 어디까지 들어야 하나요? 현재 part4까지 나와있는데 여기까지 들어도 만들 수 있는가요? 없다면 5,6 은 언제쯤 나올지 궁금합니다..
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
오브젝트 풀에서 스마트포인터를 반환하는이유
안녕하세요오브젝트 풀을 사용하는 이유가 객체의 동적할당/해제의 회수를 줄이기 위함이라 생각하는데요return std::shared_ptr<T> ptr {pop(), push};을 사용하게되면 shared_ptr 내부에서 객체를 관리하기 위한 공간이 동적으로 할당되게된다고 생각되는데요. (refcount 같은것들)그렇게되면 동적할당된 객체는 재사용이되지만 동적할당 비용을 줄이기 위함은 딱히 의미가 없어진다고 생각되는데요그럼에도 쓰는게 의미가있는가요?오히려 make_shared를 쓰는게 더 나은건 아닌지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
언리얼 클라와 실습 IOCP 서버를 연동
항상 좋은 강의 감사합니다!다름이 아니라, 추후에 언리얼 클라랑 서버를 연동하는 강의가 나중에 나온다고 하셨는데 혹시 언제쯤 나오는지가 궁금해서 질문드립니다!!
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
추가 질문) AcceptEx함수를 사용하지않고 WSAIoctl 사용이유
https://stackoverflow.com/questions/4470645/acceptex-without-wsaioctl다른 질문에서 보내주신 링크로 들어가서 확인 했습니다.추가적으로 제가 이해한 부분이 맞는지 확인해주시면 감사하겠습니다. 기본적으로 AcceptEX, ConnectEX 함수등은 아키텍처가 외부에 있기에 많은 비용이 발생하여 맵핑하여 사용한다고 생각이 듭니다 이것을 제외하고 추가적인 부분이 있을까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
AccountManager.h에서는 pch.h가 include되어 있는지 모르는데
정말 기초적인건데 갑자기 이해가 안돼서 질문 남깁니다.AccountManager.h에서는 pch.h가 include되어 있는지 모르고 AccountManager.cpp에만 include되어 있는데 어떻게 AccountManager에서는 map에 std::를 안붙이고 쓰고, int32 타입을 쓸 수 있는걸까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
echo server가 아닌 경우 연결 체크에 대한 질문
유저의 input이 없을 경우 보낼 데이터가 없는 간단한 채팅 서버라고 할 때, 이런 경우에 연결을 확인하기 위해 ping pong을 통해 지속적으로 연결 상태를 체크하나요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
데드락 관련해서 질문이 있습니다. 루키스님!
데드락 관련해서 버그가 떠서 질문글을 남깁니다.윈도우 어플리케이션을 생성해서 윈도우 메인에 서버에게 C_LOGIN을 보내는 패킷을 생성했습니다. 밑은 해당 코드입니다. bool flag = true; while (true) { if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { if (WM_QUIT == msg.message) break; if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else { CEngine::GetInst()->progress(); CEditorObjMgr::GetInst()->progress(); ImGuiMgr::GetInst()->progress(); // 렌더 종료 CDevice::GetInst()->Present(); if (service->GetCurrentSessionCount() > 0 && KEY_RELEASE(KEY::A) && flag == true) { Protocol::C_LOGIN pkt; auto sendBuffer = ServerPacketHandler::MakeSendBuffer(pkt); sendBuffer = nullptr; flag = false; } } } return (int) msg.wParam; }A를 클릭해서 서버와 연결한 후에 X를 눌러서 윈도우 창을 닫았는데, 이후 이렇게 코어글로벌이 종료될 때, GSendBufferManager를 delete하는 부분에서 타고타고 들어가서 DeadLockProfiler가 DeadLock이 존재했다고, 알려줬습니다.Server에 OnConnected가 되었을 때, 패킷을 보내면 이런 문제가 일어나지 않았는데, 원하는 때, 원하는 키를 입력해서 패킷을 보내려고 하니까 문제가 일어나네요 ㅜㅜ문제를 알 수 있을까요? 프로토 버퍼를 사용해서 주고 받고 있습니다!
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
안녕하세요 루키스님. 클라 연동에 관해서 질문을 드리고 싶습니다.
안녕하세요 루키스님.제가 비쥬얼 스튜디오에서 윈도우 어플리케이션을 만들어서 DX11포폴을 만들고 서버를 연동하려고 시도중입니다. 이 상황에서 wWinMain에 ClientServiceRef service = MakeShared<ClientService>( NetAddress(L"127.0.0.1", 7777), MakeShared<IocpCore>(), MakeShared<ServerSession>, // TODO : SessionManager 등 1); ASSERT_CRASH(service->Start()); GThreadManager->SetFlags(1); for (int32 i = 0; i < 2; i++) { GThreadManager->Launch([=]() { while (true) { service->GetIocpCore()->Dispatch(10); } }); } //밑은 DX11을 작동시켜주기 위한 함수들입니다. while (true) { if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { if (WM_QUIT == msg.message) break; if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else { CEngine::GetInst()->progress(); CEditorObjMgr::GetInst()->progress(); ImGuiMgr::GetInst()->progress(); // 렌더 종료 CDevice::GetInst()->Present(); } }이렇게 쓰레드를 생성해서 작동을 시켜주었습니다.그런데 생성된 게임 윈도우에서 X키를 눌러서 프로그램을 강제로 종료시켰는데, 이 메인 쓰레드 자체는 정상적으로 WM_DESTROY를 호출 받아서 종료되었는데, 멀티 쓰레드들이 멈추지 않고 계속 돌아 프로그램이 종료되지 않고, 좀비처럼 살아남는 현상이 계속되고 있습니다.쓰레드를 강제로 종료시키니 메모리 릭이 남고, 어떻게 문제를 해결해야할지 해결책을 찾지 못해서 이렇게 질문 남깁니다.참고) 루키스님의 패킷 직렬화#3 코드를 참조해서 만들고 있습니다!감사합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
비동기를 제대로 이해했는지 궁금합니다
1) 제가 제대로 비동기 방식을 이해한게 맞는지 궁금합니다. 비동기 방식이 어떤 함수를 호출한다면 함수를 지금 바로 처리하지 않고 예약같은 개념으로 요청한 함수를 나중에 처리하고 그동안 요청한 함수외에 다른 부분을 실행하는걸로 이해를 했는데 맞는건지 궁금합니다.2) 만약에 제가 이해한 방식대로 비동기가 진행이 된다면 수업에서 진행한 ::WSAWaitForMultipleEvents(1, &wsaEvent, TRUE, WSA_INFINITE, FALSE); 코드에서 블로킹 방식처럼 진행하는데 이 부분은 비동기와는 맞지 않는 부분아닌가요??
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
데드락 탐지
데드락 탐지에 관련해서 궁금한게 있어서 질문드립니다.아래의 코드로 lock_guard를 이용해서 데드락을 탐지 하려고하는데 데드락이 되는 상황이 발생하고, 탐지는 안되는 경우가 가끔 발생하네요... DeadLockProfiler는 예제의 코드를 복사해서 사용했습니다. #include "pch.h" #include <iostream> #include "DeadLockProfiler.h" mutex lock1; mutex lock2; void Test(); void Test2(); void Test() { DeadLockProfiler::GetInst()->PushLock("Test"); lock_guard<mutex> gurad(lock1); Test2(); DeadLockProfiler::GetInst()->PopLock("Test"); } void Test2() { DeadLockProfiler::GetInst()->PushLock("Test2"); lock_guard<mutex> gurad(lock2); Test(); DeadLockProfiler::GetInst()->PopLock("Test2"); } int main() { thread th1([=] { while (1) { cout << "test" << endl; Test(); this_thread::sleep_for(100ms); } }); thread th2([=] { while (1) { cout << "test2" << endl; Test2(); this_thread::sleep_for(100ms); } }); th1.join(); th2.join(); return 0; }
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
템플릿 흑마법을 보고 질문 글을 남깁니다.
Job Queue #2의 영상을 보고 질문드립니다.이 영상을 보고 저번에 메모리 관련해서도 보고 느낀 것인데, 템플릿 흑마법을 따로 공부할 수 있는 책이나 가이드가 있을까요?루키스님의 영상을 볼 때는 템플릿 흑마법이 이해가 가긴 하는데, 이걸 스스로 짤 생각을 하니 도저히 엄두가 안나서 공부가 필요할 것 같아 이렇게 질문 글을 남깁니다.