월 66,000원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
책 추천 문의드립니다.
우선 좋은 강의 감사합니다. 강의 초반 Modern C++ Design 책 추천을 주셨는데요, 이 외에 추천 해주실 책이 있으신지 문의 드립니다. (개인적으로 추천해주시는 top5책을 알고싶습니다.) 코드를 짜면서 생소한 패턴를 만날때다마 블로그에 떠도는 글을 보면서 알음 알음 알아가고 있는데요, 혹시 이러한 지식들을 체계적으로 쌓고 싶은데, 해당 책 외에 추천 가능하실까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Recv (TCP) 관련 질문이 있습니다.
2:05초에서 TCP로 보낼경우 한 번에 패킷이 다 오지 않을 수 있다고 했는데요.위에 그림과 같이 1 클라이언트가 16byte 보내고2번 클라이언트가 3바이트 보낸다고 했을 때,1번 클라이언트 16바이트가 다 도착하지 않았는데 2번 클라이언트의 3바이트가 끼어들 수 있나요? 그럼 1번 클라이언트의 패킷이 끝까지 왔는지 판별하기 어려울 것 같은데요. TCP 구조를 잘 몰라서 동시에 패킷을 보냈을 때 순차적으로 접근해서 해결이 되는건지(IO단에서) 아니면 통신 두절이나 통신 오류(물리적 오류)로 인해 지연 현상이 생겨 패킷이 꼬일 수 있는지 궁금합니다. 요약하자면 1번클라이언트 패킷이 전송완료(받기완료)가 되지 않은 상태인데 2번 클라이언트의 패킷이 끼어들 수 있는지 궁금합니다. 이럴때는 처리를 어떻게 해야하나요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
전송 순서 관련 질문입니다.
Send 코드를 보던 중 궁금증이 생겼습니다. 컨텐츠 구현시 정확히 Send를 호출한 순서대로 패킷이 가야 하는 경우가 있는가? 입니다. 만약 1번 스레드가 Send 호출 후 connected 확인만 하고 멈추고, 2번 스레드가 이후에 Send를 호출해 lock을 잡을 경우 1->2 순서로 호출했지만 데이터는 2->1 순서로 전송될 것입니다. 이렇게 자세하게 따져야 하는 경우가 있는지, 있다면 send 시작부터 exchage까지 lock을 잡으면 해결되는 문제인지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
sendQueue 관련 질문입니다.
강의를 들으며 1send + sendQueue를 사용하는 경우의 장점은 1.더 많은 클라이언트를 받을 수 있다. 2.TCP 헤더가 적게 붙어 네트워크상 이점이 있다. 이렇게 생각했습니다.하지만 실제로 서버를 만들다 보니 동시 send가 불가능해 대부분의 시간을 lock에 소비했고, n send에 비해 동시접속 가능한 클라이언트 수가 줄어들었습니다.그럼 2번 장점이 확실한가? 궁금해서 wireshark로 확인해 봤을 때 별 차이가 없었습니다. 큐에 넣지 않고 WSAsend를 많이 호출해도 os가 패킷을 뭉쳐 보내는 것 같습니다. 지금 방식의 장점이 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
AcceptEvent를 하나만 사용할때 세션관리
안녕하세요 제가 궁금한 게 있어서 질문드립니다.위 사진과 같은 상황이 발생하면 AccetEvent를 하나만 사용하기 때문에 애써 힘들게 구한 세션이 Register 할 때 초기화 돼버리지 않나요 ㅠㅠ? Register를 하기 전에 따로 세션을 저장해야 하는 거 아닌가요? 혹시라도 다음 강의에서 다르는 주제라면 죄송합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Memory Pool#2 삭제 Lockfree stack 과의 값 교환 차이가....?
이전에 Lock free stack 에서는 ABA problem 이 발생하지 않는다고 별도로 들고 있었기 때문이라고 하셨는데 이전에도 링크드 리스트 처럼 포인터를 들고 있던 방식이고 현재 이것도 그것과 유사한 방식인데 왜 이전에는 ABA 가 발생하지 않았다고 하는건지 잘 이해가 가질 않네요 이전 lock free stack 에서 삭제 할때의 로직과 크게 달라보이진 않는것 같은데요..이전 lock free stack 에서도 ABA Problem 이 발생하지 않나요?차이점이 명확하게 어떤 부분인지 모르겠습니다..답변좀 부탁드려요! Memory Pool#2 시간은 26:55 초에서 정도에서..
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
스핀락 질문
CAS 의사코드를 설명하시면서 while(_locked){}_locked=true;이 코드를 한번에 실행할 수 있다고 하셨는데 두 스레드가 동시에 if문에 진입한다면 동일한 결과를 가지지 않을까라는 생각에서 의사코드 자체를 SpinLock 클래스 안에 새로운 매서드로 만들어서 실행해보니 0이 출력되지 않았습니다.어떤 원리로 두 코드가 한번에 실행되는지와 cp매서드를 어떻게 수정해서 compare_exchange_strong처럼 동작하게 할 수 있는 지 궁금합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
C++ ORM 질문드립니다
1 .C++은 EntryFramwork같은 라이브러리가 없을까요?실무에서는 ORM은 잘 사용하지 않는다고 하셨는데 혹시 사용을 안하는 이유가 있을까요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
강의 수강 후 개인 프로젝트 적용
수강 후, 대학 동아리 수준에서 내용을 제대로 습득했다는 전제 하만든 게임과 서버를 연동할 능력을 갖출 수 있나요?동아리에서 mmorpg를 만들어 보려 하는데 서버를 담당하게 되어 미리 공부하려 합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
이해한 내용이 맞는지 궁금합니다
데드락은 서로 락을 걸어버려 상대가 락을 풀때까지 하염없이 기다리는 상태먼저 AccountManager에서 ProcessLogin이 먼저 실행이 되었다고 가정했을 때 lock_guard를 사용하여 ProcessLogin이 끝날 때까지 다른 쓰레드의 AccountManager 접근을 막아버린다. 그와 거의 동시에 UserManager의 ProcessSave도 실행이 되면서 ProcessSave를 실행하는 쓰레드가 다른 쓰레드의 접근을 막아버린다. 이 때 ProcessLogin에서 UserManager::Inst()->GetUser를 실행하면 다른 쓰레드에서 UserManager에서 접근하지 못하도록 락을 걸고 GetUser를 실행해야 하는데 먼저 ProcessSave에서 user lock을 걸었기 때문에 추가적인 락을 하지 못하게 된다.또 GetAccount를 실행할 때도 ProcessLogin에서 먼저 account lock을 걸었기 때문에 GetAccount에서 lock_guard를 하지 못하고 멈춰서 다른 곳에서 account lock을 풀어줄 때까지 하염없이 기다리게 된다. 안녕하세요 강사님이렇게 이해를 했는데 맞는지 궁금합니다!
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
w->r (0) r -> w(x)
23:41초 에서w->r (0)r -> w(x) 라고 설명하셨는데 코드를 보면 write 를 누군가 했다면 write 를 한 스레드가 풀어주기 전까지는 다른스레드에서 read 는 못하는 상태가 되고 누군가 read를 했다면 readcount 라 0 이될때까지 다른 스레드에서 write 를 할 수 없는 상황인것 같은데 정리하자면 read 아니면 write 둘중 하나만 가능한 상태인것 같은데w->r (x)r -> w(x) 이렇게가 맞는거 아닐까요?뭔가 실행 흐름상의 맥락을 잘못 이해하고 있는건지 궁금합니다!
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
한가지 에러와 한가지 질문이 있습니다
한가지 에러는 WRITE_LOCK 부분인데요void MemoryPool::Push(MemoryHeader* ptr){ WRITE_LOCK; //Pool에 메모리 반납 queue.push(ptr); allocCount.fetch_sub(1);}부분에서 WRITE_LOCK에서 에러가 나고 있는 상황입니다.Push와 Pop 둘 다 동일합니다.심각도 코드 설명 프로젝트 파일 줄 비표시 오류(Suppression) 상태오류(활성) E0300 바인딩된 함수에 대한 포인터는 함수를 호출하는 데에만 사용할 수 있습니다.이런 에러가 나고 있는 상황이고 한가지 질문은 Memory부분에서if (allocSize > MAX_ALLOC_SIZE) { header = reinterpret_cast<MemoryHeader*>(malloc(allocSize)); }부분에서 왜 static_cast를 쓰지 않고 reinterpret_cast를 사용하는 건가요? static_cast를 사용했을 때 발생할 수 있는 문제점이 있나요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
10014 에러 관련 질문
위 스크린샷과 같이, 10014 에러 코드가 뜨면서 딱 한 번 데이터를 주고받은 다음에 진행이 되지 않았습니다.그리고 디버깅 및 코드 비교를 통해 RecvBuffer.cpp 부분에서 아래와 같은 실수가 있었기에 위와 같은 오류가 발생하게 된 것임을 알게 되었습니다.그런데 강의에서 저는 이 버퍼의 크기를 크게 잡아주는 것이 일종의 성능향상과 편의를 위함으로 이해했었습니다. 그리고 처음에는 10014 오류가 주소와 관련한 오류라는 것을 보고, NetAddress, Session, Listener를 집중하여 분석하느라 원인을 찾는 데에 오래 걸렸었습니다. 위 상황에서 저 버퍼의 크기를 resize 해주는 과정이 잘못된 것이 왜 10014 오류를 발생시키게 되었는지 의문점이 들었습니다. 혹시 10014 오류가 발생했던 정확한 원인이 무엇이었을지 알려주실 수 있을까요? (코드 : https://drive.google.com/file/d/1Yjn7lKGXzTKfNuBmRBw66t7AkZgbmGIO/view?usp=sharing )
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
push 에 관한여 해제..
push 에서 push 스레드가 3개 있다고 했을때 3개 모두다 T* oldData = nullptr; 이 구문 까지 실행 됐다는 가정 하에 질문을 해보면..if (oldTail.ptr->data.compare_exchange_strong(oldData, newData.get())){ oldTail.ptr->next = dummy; oldTail =tail.exchange(dummy); [........] FreeExternalCount(oldTail); 현재 스레드에서 [........] 부분 까지 실행 되다가(FreeExternalCount(oldTail); 이건 실행 되지 않고..)다른 push 스레드들 에서 이 구문을 들어오지 못한 push 스레드는들은 oldTail.ptr->ReleaseRef(); 이 계속 반복적으로 계속 호출 되면서 internalCount 값이 -2 이상을 훨씬 더 넘는 상황이 발생 할 수도 있을것 같은데현재 스레드는 ... 에서 계속 처리가 되지 않고 스케줄러에 의해 지연되고 있다 가정한다면 internalCount 카운트의 계산이 이상해지고 while 문은 언젠가 끝나긴 하겠지만 internalCount 가 -로 많이 쌓이게 될 경우에는 메모리가 삭제 되지 않고 누수가 될것 같은데요..? 맞나요?아직 pop 함수는 보진 않았습니다만.. 카운팅 방식이 맞나해서 질문 남깁니다
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
특정 영상이 재생되지 않습니다
나머지 영상은 괜찮은데 Thread Local Storage 영상이 어제부터 계속 재생이 안되는데 인프런 서버 문제일까요? 혹시 해결 방법이 있을까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
클라에서 이상하게 패킷을 대량으로 보낼때 질문입니다.
안녕하세요 Rookiss 선생님!"일정 시간 동안" 클라가 서버로 WSABuf 와 같이 한번에 여러 패킷 ID와 데이터를 보내는 경우가 아닌,하나의 일정한 덩어리 "패킷 ID+데이터" 단위로 여러 개 보낼 경우서버가 recv 과정에서 이상하게 클라로부터 패킷을 여러개 받을 때어떤 패킷 아이디로 이상하게 왔는지 분석하는 효율적인 방법이 있을까요?클라에서 WSABuf와 같이 뭉쳐서 보내면 서버 recv 단에서 패킷 크기가 많을 경우 따로 처리하면 되겠지만.클라가 일정 크기로 하나의 패킷 ID+ 데이터 단위로 보내면 계속 패킷 크기를 카운트 해야 한다는 문제점이 있을 거 같습니다.또한 어떤 패킷 아이디가 이상한가? 분석하려면 서버측에서 클라가 보낼 수 있는 패킷 아이디 C_ 개수만큼 배열을 설정하고패킷 아이디 마다 카운트를 늘리고 다시 0으로 초기화하는 작업은 비효율적이거 같아서 질문드립니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
동기화 문제
질문.1 push 쪽에서 node->next = head; 이 로직이 실행 된 이후 head.compareexchange_weak 이 실행 되기전pop 이 다른스레드에 의해서 먼저 실행 된다면 _head 값이 달라질것이고 이와 반대 되는 상황도 있을것 같은데그럴때에도 정상 작동 하는건가요? 질문2.반대로 pop 쪽에서 먼저 실행되고 질문1 처럼 실행 됐을때도 정상 작동 하는 걸까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Push에서 exchange 사용 이유
140번줄에 있는 _tail.exchange(dummy); 부분에서exchange를 사용하는 이유가 궁금합니다.해당 부분에서 필요한 기능은 store만 해도 될 것 같다는 생각이 듭니다. 그래서 139번줄에 있는 store로 바꿔서 테스트 해봐도 일단은 문제가 없었는데요.혹시 제가 놓치는 다른 이유가 있는 건가요?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Event와 CV 차이
프로듀서에서 빠르게 데이터를 밀어주는 경우Event는 이벤트와 락 부분이 묶여 있지 않기 때문에 큐에 데이터가 있음에도컨슈머가 실행되지 못하고 프로듀서가 계속 실행되는 경우가 생기지만,CV는 락과 조건체크 부분이 묶여서 그런 일을 방지해준다.즉 데이터가 있으면 무조건 팝 할수 있게 된다.이렇게 이해하면 맞을까요 ?
- 해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
결국 atomic도 lock도
그러면 결국 유저가 직접 구현해서 경쟁상태를 해소할 방법은 없는건가요 ?어셈블리 명령어가 쪼개져서 생기는 문제니깐 원자적 연산이나 lock 같은것을 응용 프로그래머가직접 구현 할수는 없는것인가여 ...?다른책에 CAS 함수가 하나 있길래 적용해볼려고 했는데 제가 잘못 이해한건지..아니면 이것도 결국 비교->대입 하는 부분을 원자적으로 묶을 방법이 없어서 불가능한 의사코드인가요#include <iostream> #include <thread> using namespace std; class SpinLock { public: SpinLock() : mylock(false), expected(false), desired(true) {} void lock() { while (CompareAndSet(expected, desired) == true) { static long time = 0; cout << " I am Spining now.." << time++ << endl; expected = false; } } void unlock() { mylock = false; } bool CompareAndSet(bool expected, bool desired) { bool original = mylock; if (original == expected) mylock = desired; return original; } private: bool mylock; bool expected; bool desired; }; long sum; SpinLock spin; void Add() { for (int i = 0; i < 1'0000'0000; i++) { spin.lock(); sum++; spin.unlock(); } } void Sub() { for (int i = 0; i < 1'0000'0000; i++) { spin.lock(); sum--; spin.unlock(); } } int main() { thread t1(Add); thread t2(Sub); t1.join(); t2.join(); cout << sum; return 0; }