묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[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의 영상을 보고 질문드립니다.이 영상을 보고 저번에 메모리 관련해서도 보고 느낀 것인데, 템플릿 흑마법을 따로 공부할 수 있는 책이나 가이드가 있을까요?루키스님의 영상을 볼 때는 템플릿 흑마법이 이해가 가긴 하는데, 이걸 스스로 짤 생각을 하니 도저히 엄두가 안나서 공부가 필요할 것 같아 이렇게 질문 글을 남깁니다.
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
혹시 언리얼 클라에서는 WSA Recv가 아니라 그냥 recv 사용해야 하나요?
서버랑 언리얼 연동 후 단순한 데이터 교환은 되는데, 패킷을 받아 스폰 기능을 사용하려고 하면 IsInGameThread() 라는 에러가 뜹니다. 대충 느낌을 보아하니 뭔가 외부 쓰레드? 그런 걸 차단하는 느낌이 드는데...Dispatch 해주는 워커쓰레드한테 FRunable 해줘도 해결 되지 않아서 질문 드립니다.. 혹시 다른 사람은 어떤가 싶어, 코드를 보니 서버는 IOCP를 사용하되, 언리얼에서는 그냥 recv만 사용하더군요.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
강의에서 allocate 함수 두번 호출되는 것에 대해
강의 7:26 초 쯤에서의vector<Knight, StlAllocator<Knight> v(100);이후 allocate 함수 호출 과정에서 처음에 1, 두번째 100이 호출 되는 이유는 무엇인가요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Server Service에서 함수포인터 사용관련해서 질문을 남깁니다.
using SessionFactory = function<SessionRef(void)>; Service(ServiceType type, NetAddress address, IocpCoreRef core, SessionFactory factory, int32 maxSessionCount = 1); Service의 생성자는 이런식으로 SessionFactory라는 함수포인터를 받고 있습니다. 그런데 함수포인터를 전달하지 않고, ServerServiceRef service = MakeShared<ServerService>( NetAddress(L"127.0.0.1", 7777), MakeShared<IocpCore>(), MakeShared<GameSession>, // TODO : SessionManager 등 100); 이렇게 MakeShared로 생성된 GameSession 클래스를 전달해도 잘 동작하는데, 함수포인터 형식에 클래스를 그냥 사용해도 잘 동작하는 이유가 궁금합니다.MakeShared의 함수에서 ()를 사용하지 않으면, 내부적으로 xnew함수만 전달되어서 그런것인가요? 제가 이해한게 정확한지 모르겠어서 질문을 남깁니다. (한번도 function을 이렇게 사용한적이 없어서 모르겠네요 ㅜㅜ)
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
섹션4 네트워크 라이브러리 제작의 IOCPCore부분에 질문이 생겨 글을 남깁니다.
서버가 받은 클라이언트 소켓의 아이피와 포트를 출력하고 싶어서 Listner의 ProcessAccept함수 안의 출력부분에 코드를 이렇게 짰습니다.//..................... wstring IpAddress = session->GetAddress().GetIpAddress(); uint16 port = session->GetAddress().GetPort(); cout << "Client Connected!aaa" << endl; wcout << IpAddress << port<<endl; //........................그런데 출력이 계속 Client Connected! 라고만 뜹니다. 문자열을 아무리 변경해도 계속 이렇게 뜨네요. 포트문제인가 싶어서 컴퓨터를 껏다키고 해보아도 여전히 Client Connected!라고만 뜹니다. 이유가 무엇일까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
클라이언트 연동 질문입니다
안녕하세요현재 해당 강의 수강중에 궁금한 점이 있어서 질문드립니다제가 4인이 한 세션에 들어갈 수 있는 게임을 만들고자 하는데 (유니티로 제작할 예정입니다) 유니티 클라이언트에 로비 레벨이 있고 각 클라는 로비 레벨에서 매칭 신청을 하면 c++서버에서 매칭 신청 클라를 데디서버 프로세스를 띄우고 해당 데디서버를 통해 세션플레이를 진행하고자 합니다제가 유니티를 안해봐서 유니티에도 언리얼 데디서버 같은 기능이 있는지 혹은 직접 데디서버 역할을 하는 c# 프로그램을 구현해야하는 것인지 궁금합니다.rookiss님 유니티 강의에서 다루는 내용이 해당 내용을 포함하는지도 궁금합니다
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
atomic<uint32> _popCount 관련
안녕하세요. 궁금한 게 있습니다._popCount에 관해 질문이 몇 개 보이는데 좀 다른 내용이지만 저도 관련해서 질문합니다._popCount 변수가 Pop 함수를 실행하는 쓰레드 개수를 추적하는 것인데요, Pop함수를 실행하는 쓰레드의 개수가 아닌, Node* oldHead = _head;이 코드에서 얻게 되는 동일한 포인터를 참조하는 쓰레드의 카운트를 추적해야 하는게 아닌가 하는 의문이 듭니다. 이를테면 Pop을 실행하는 쓰레드가 한 50개가 있다고 하면 계속해서 _popCount는 1이 될 수가 없을 거 같은데요, 실제로 테스트 해봤는데 Delete 함수로 진입을 안 합니다. 제가 잘 못 생각하는 부분이 있을까요?
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
공부 방향에 질문이 있습니다!
원래는 1년 전에 졸작을 만들기 위해 이 강좌를 참고하다가, 당시 수준으론 어려워서 대신 C# 강좌를 통해 유니티를 연동한 멀티플레이 VR 게임 졸작을 완성했습니다. 그러다가 이제 졸작 발표가 끝나고 현재 이 강좌를 보고 있는 중인데, 다만 오랜만에 찾아보니 [게임 프로그래머 입문 올인원]이라는게 있길래 같이 보는 중입니다. 그렇게 두 강좌를 같이 참고해서 보다 보니 이 강좌에서는[게임 프로그래머 입문 올인원] 에선 나오지 않는 여러 디테일한 내용들이 많은 걸 알 수 있었습니다. 일단 졸작에서 C# 서버를 만들어본 덕분인지 MSDN 문서를 참고하면 대충 강좌를 보지 않아도 서버 틀은 만들 수 있게 되었는데, 사실 이 강좌에서 나오는 디테일한 내용들은 여전히 머리가 빙빙 도는 상황입니다. 정확히 말하면 [게임 프로그래머 입문 올인원]의 서버는 어느정도 혼자 할 수 있을거 같은데,이 강좌에서 나오는 디테일한 내용을 혼자 채워넣으려고 하면 힘들다고 해야 할까요. 당장 데드락 사이클을 체크하는 내용만 봐도 알고리즘 공부를 다시 해야 한다는 걸 느끼는 중입니다. 원래 코테용으로 bfs나 dfs를 나름 공부하기는 했지만, 지금 지식으로는 저런 내용을 혼자 만드는 건 엄두가 나질 않습니다. 아무튼 감사하게도 일단 루키스님의 강좌가 있으니 지금은 이걸 보면서 공부하면 되는 것인데, 나중에 취업을 하면 강좌에 나오지 않은 다른 디테일한 내용들은 어떻게 공부를 해야 하는 걸까요? C# 강좌의 마지막에서 나오는 여러 기법들이나 해킹 관련 이슈의 대처법 같은 건 지금처럼 혼자 만든다고 터득할 수 있는게 아닐텐데 말입니다.아니면 취업후에도 따로 학원을 다녀야 하는 걸까요?만약 다닌다면 학원에서 어느정도의 내용을 배울 수 있는 건가요? 루키스님 강좌를 들어보면 중간에 서버 학원에 대한 간략한 언급들이 있던데 말입니다.일단 다음 학기를 마지막으로 졸업인지라, 이번에는 언리얼 포트폴리오 제작을 위해, 다음 강좌가 나오기 전까지 혼자 언리얼이랑 서버 연동을 도전해보는 것도 좋아보여서 해보는 중에 의문이 들어 질문드립니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
페이지 질문
메모리를 페이지 단위로 관리하신다고 하셨는데VirtualAlloc을 통해서 int를 따로 2번을 요청하게 되면 위에 그림처럼 int가 연속적으로 배치되는게 아니라 페이지 단위만큼 떨어지게 메모리가 배치가 되는건가요??만약에 저렇게 배치가 된다면 size를 그대로 넣지 않고 직접 구해서 넣는 이유가 뭔가요??
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Event Vs Condition_Variable
제목 그대로 Event와 Condition_variable의 차이가 단순히 Kernel 이냐 User Level이냐의 차이인지가 궁금합니다. CV에서는 조건을 추가해서 코드상으로 봤을 때, 깔금해지는 것은 알겠는데Event와 동일하게 Producer에서 Notify_one을 실행 하더라도 Consumer에서 바로 Lock을 잡지 못한다면 Producer가 한 번더 실행될 거같은데 이부분은 제가 이해를 못한건지 잘 모르겠습니다. 정리 -> cv를 이용해서 notify_one함수를 호출해도Producer에서 바로 Lock잡아버리는 상황이 발생하지 않나라는것. cv 장점 : 코드가 깔끔해지고, User_Level에서 동작한다. 다른것은 Event와 동일하다? 라고만 이해하면 되는지 궁금합니다.
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
안녕하세요 Client 를 WinAPI Project로 붙여보려고 하는데
Client의 생성된 Window창 x를 누르면 윈도우 창이 종료되지 않고 Client에서 굳이 Console창을 열어 마우스로 x를 눌러야지만 닫기는데 원인을 못찾겠습니다.. 혹시 짐작갈만한 원인이 있을까요?예상으론 Thread가 Join상태에서 끝나질 않아 발생하는 현상같은데 그럼 강제로 Thread로 생성해뒀던 무한Loop를 강제로 종료하는 방법을 작성해야할까요?
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
쓰레드매니저 질문
... void ThreadManager::Launch(function<void(void)> callback) { LockGuard guard(_lock); _threads.push_back(thread([=]() { InitTLS(); callback(); DestroyTLS(); })); } ... --------------------------------------------- int main() { for (int32 i = 0; i < 5; i++) { GThreadManager->Launch(ThreadMain); } GThreadManager->Join(); }쓰레드 매니저 예제 코드의 일부인데요, 위 코드에서 다음과 같이 InitTLS();GThreadManager->Join();두 곳에 브레이크 포인트를 걸었는데 신기하게 Join에 먼저 브레이크가 걸리네요. Launch 함수가 순차적으로 실행되고 메인함수의 반복문을 빠져 나온다음에 Join이 걸릴거 같은데요.Launch 함수가 쓰레드 함수라면 그럴 수 있겠지만 ThreadManager 자체는 쓰레드가 아닌데 왜 그런 것인가요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
안녕하세요. xdelete 관련 질문이 있습니다.
아래코드에서 xdelete에서 굳이 소멸자를 호출해줘야 하는 이유?가 궁금합니다.강의내용이 new, delete 함수를 재정의해서 사용하는거라서 명시적으로 xdelete를 사용하기 때문에 Knight 소멸자에 객체를 해제하는 코드가 없는것 같은데, 그렇다면 굳이 소멸자를 호출하지 않아도 되지않나요?만약 소멸자에 객체를 해제하는 코드를 구현해 놓는다면 사실상 free를 두번하는거지 않나 싶어서요. template<typename Type> void xdelete(Type* obj) { obj->~Type(); xrelease(obj); }