월 66,000원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
AcceptEx 질문있습니다.
AcceptEx가 실패가 나는 경우 즉 , AcceptEx호출 자체가 false가 나고, 이때 GetlastErrror가 WSA_IO_PENDING이 아닌경우나 , AcceptEx의 호출로 IOCP 에서 Pending중일때 모종의 이유로 GQCS에서 AcceptEx pending에 대한 실패가 리턴되는경우 listen socket이 close되었거나, 어찌되었든 더이상 유저를 받지못하는 상황일 수 있는데 이럴때 서버에 강제로 CRASH를 내도록 해도 될것같은데, 혹시 이렇게 하면 안될 이유가 있을까요?? (AcceptEx를 호출할때 close된 session 소켓을 전달하는 경우는 없고, AcceptEx의 호출결과로 IOCP 유저접속을 대기중인상태(Pending)일때 session socket이 close되거나 session이 삭제되는 일은 일체 없다고 가정합니다. 물론 listen socket은 닫힐 수 있지만, listensocket이 닫히면, 서버를 유지시켜줄 이유가 없다고 생각되긴 합니다.)
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
저가 정리한게 맞는지가 궁금합니다
요약한게 맞는지 확인해주실 수 있나요? 1. Pop은 현재 head를 따로 oldHead로 저장하고, 이것이 nullptr이 아니란 소리는 head가 존재한다는 뜻, 즉 1개 이상 스택에 값이 존재한다는 뜻임 2. 스택에 값이 1개 이상이면 oldHead는 nullptr이 아닐 것이고 pop을 한번 했을 때 oldHead에 head가 제대로 값이 들어갔다면 while문을 통과하면서 _head=oldHead->next;가 원자적으로 실행되고, 아래쪽을 쭉 실행하다가 TryDelete 함수가 호출될 것임 2-1. 이때 만약 다른 Pop 쓰레드들이 있다고 하면, 요놈들은 첫 Pop에서 _head가 oldHead->next로 바뀐것으로 인해 while문을 통과하지 못하므로 oldHead=_head가 실행되어 다시 while문이 불려져서 다음 원소를 상대로 pop을 진행함 -------------------- 이후는 TryDelete입니다 3. popCount가 1인 경우 : TryDelete가 실행되는 순간에도 popCount가 1이라면 아직은 Pop이 다른 쓰레드로 호출되지 않은 상태임. 3-1-1. pendingList를 읽어 삭제하려고 하는데, 이걸 읽었는데도 popCount가 아직 1이라면 Pop이 pendingList를 읽는 사이에 한번도 호출되지 않은 것이므로, 읽은 pendingList와 연결된 모든 노드를 이참에 삭제함 3-1-2. pendingList를 읽어 삭제하려고 하는데, 이걸 읽은 사이에 popCount가 증가하여 Pop이 다른 쓰레드에서 호출됐다는 걸 알았으니 읽어들인 pendingList를 다시 돌려놓는다. 3-2. pendingList도 다 삭제햇으니(돌려놨으니) 현재 노드를 삭제해주면 된다. 4. popCount가 1 초과인 경우 : TryDelete가 실행되는 순간에 popCount가 1을 넘어버렷다면, Pop이 다른 쓰레드에서 호출된 상태이므로 지금 당장 삭제하지 말고 삭제 예약만 해놓도록 한다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Job Queue가 Message Queue, Event Queue와 동일한 용어인가요?
서버를 공부하니 이런저런 다양한 큐들이 많이 보이던데 혹시 이번 강의의 잡큐가 메시지큐, 이벤트큐와 같은 방식일까요??
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
언리얼 게임서버 연결 질문
안녕하세요 루키스 강사님 두가지 질문이 있는데요 1. 게임서버 강의를 들으면서 개발한 서버를 언리얼에 연결하는건 유니티 강의때와 큰 틀은 비슷한가요? 2. 혹시 루키스 강사님이 봤던 책 중 참고할 만한 책이 있나요? 찾아봤는데 시중엔 대부분 언리얼 자체 네트워크를 사용하는 예제만 있는것 같더라고요
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
추가할만한 기능
우선 인생 강의 정말 감사드립니다. 도움이 정말 많이 되네요ㅠ,ㅠ 강의 시간과 분량 상 필수적이고 핵심적인 것만 알려주셨을 거 같은데, 강의에서 가르쳐주신 것처럼 자기만의 서버 프레임워크를 만들어갈 때 더 추가할 만한 기능이 있을까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
서버 데이터베이스
서버 데이터베이스를 구축할 때, 하둡 카프카 스파크 등 분산 처리 스택도 같이 다루는 경우도 있나요? 위 분산 처리 스택에 대한 경험이 있으면 취업 시 유리한 점이 있을까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
sendQueue에 1개 이상 쌓이는 이유
안녕하세요 선생님 디버깅을 해봤는데 생각한대로 잘되지않아서 _sendQueue 버퍼가 쌓이는 방식이 제가 이해한게 맞는건지 의문이 들어서 질문드립니다. 일단 send()에서 _sendQueue에 버퍼를 넣어주고 _sendRegistered를 true 변경후 RegisterSend()를 호출합니다. 그리고 _sendQueue를 모두 비운후 WSASend까지 성공을하면 send()에서 걸었던 lock이 해제가 됩니다. 그후에는 다른 쓰레드에서 동일한 세션으로 send를 요청할경우 send()를 받고 _sendQueue에 버플 넣을수는 있으나 ProcessSend()에서 _sendRegistered를 false로 변경하지않았을경우 send()에서 RegisterSend()를 호출할수 없습니다. 그후 기존에 send가 진행되고 있던 쓰레드가 실행될경우 ProcessSend()에서 바로 RegisterSend()함수를 호출하게 되고 그때는 _sendQueue에 쌓여있는 버퍼를 볼수있게 됩니다. 제가 이해한게 맞는건가 싶어 질문드립니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ProcessSend에 대해서 질문이 있습니다.
WRITE_LOCK; if (_sendQueue.empty()) _sendRegistered.store(false); else RegisterSend(); ProcessSend에서 WRITE_LOCK의 의미가 잘 이해가 되지 않습니다. 이미 큐에 대한 작업을 할 때 WRITE_LOCK을 일일이 잡아주고 있는데 ProcessSend에서 굳이 다시 락을 잡는 이유가 무엇인가요? 그리고 Lock(); if (_sendQueue.empty()) _sendRegistered.store(false); Unlock(); else Unlock(); RegisterSend(); 와 같이 락의 범위를 잡으니 패킷 유실이 발생하는데 이렇게 잡으면 안되는 이유를 전혀 모르겠습니다..
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Send관련 질문입니다.
로그도 찍어보고 브레이크 포인트도 잡아보면서 해보아도 도저히 무슨문제인지 파악이 안되서 질문드립니다. 핸들러함수안에서 아래와같이 1번패킷과 2번패킷으로 Send를 두번 연속호출했을 때 클라이언트에선 2번패킷으로만 두번 호출되더라구요. 근데 또 1번패킷과 2번패킷 Send사이에 브레이크 포인트로 지연시간을 잠깐 둔 후 실행하면 클라이언트에서 제대로 1번 2번 순서대로 받게 되더라구요. 왜 이런 현상이 나오는지에 대해 질문드립니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ChunkBuffer 관련 질문입니다
1. 4096바이트로 chunk 버퍼를 잡아놓은 후 다 사용하면 삭제하고 다시 만드는 이유가 뭔가요? 그냥 writePos를 0으로 옮기는 등 초기화하여 사용하면 되지 않나요? 2. ThreadLocal로 지정해 놓은 변수들은 getqueuedcompletionstatus로 임의의 스레드가 깨어났을 경우에도 깨어나기 전까지 저장해놓은 상태가 계속 유지되나요? 예를 들어 스레드 1에서 sendbufferchunk에서 100바이트 사용했다면 Dispatch하여 getqueuedcompletionstatus에서 깨어났을 때 여전히 sendbufferchunk가 100바이트를 사용한 상태를 유지하나요? 스레드 내에서는 일종의 전역변수처럼 사용되는거 같습니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
현업에서 서버 구축
안녕하세요. 두 가지 질문이 있습니다. 현업에서 서버 구축할 때 게임 만들 때 마다 매번 socket 기반작업과 관련된 구현(iocp 로 socket session manager, serializer 등등) 을 하나요? 웹서버 프레임워크처럼 게임서버 프레임워크같은건 사용 안하나요? 게임마다 조금씩은 다르겠지만 공통적으로 구현해야 하는 부분이 많을 것 같아서요. 만약 사용한다면 어떤 프레임워크를 자주 사용하나요? 또 다른 질문이 있는데요. object 간의 collison 같은 건 서버에서 확인하나요? 예를 들어 철권같은 게임에서 player 1 이 player2 를 때렸다면, 맞았다는 판단은 서버에서 내린 후 player1 과 player2 에게 전달되나요? 만약 그렇다면(서버에서 collison을 확인한다면) 서버에 물리엔진? 같은게 구현되어 있어야 할 것 같은데 그러면 좀 이상한 것 같고 그렇지 않다면(서버에서 collison을 확인하지 않는다면) 유저가 colision 을 판단해야 하는데 시간 차이때문에 서로 다른 판단이 일어날 수도 있고 packet 을 조작해서 맞았다고 하기도 쉬울 것 같아서요. 철권같이 판단에 아주 민감한 게임을 만들려고 하는데, 어떻게 하는게 좋을까요? 이미 알려진 아키텍쳐같은게 있다면 키워드로만 알려주시면 제가 찾아보겠습니다. 강의 잘 듣고 있습니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Lock-Free Stack 질문입니다
Lock-Free Stack부분 강의 듣다가 너무 어려워서 그런데 실무에서도 사용하는 부분이라 완벽하게 짚고 넘어가야 하는 부분인가요?? 그리고 Lock-Free Stack 의 중요도를 별 5개중 몇개라고 생각하시나요??
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
WSASend GetQueuedCompletionStatus 함수 질문드립니다.
안녕하세요. WSASend함수를 호출할 때 소켓정보와 소켓버퍼 오버랩드를 넘겨주는데 여기서 작업이 완료되면 IOCP의 완료큐에서 작업이 완료된 I/O를 꺼내올 때 만약 IOCP에 완료키를 Session객체로 등록했을 때 1번소켓을 들고있던 Session에서 2번 소켓을 대상으로 WSASend함수를 호출하면 IOCP에서 완료키를 꺼내오는건 1번소켓을 들고있는 Session인가요? 아니면 2번소켓을 가진 Session을 반환하는지 궁금합니다. ex) 1번 소켓을 가지는 Session WSASend(2번소켓,~~~)
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
DoGlobalQueueWork함수에 대한 질문입니다.
쓰레드들이 DoGlobalQueueWork함수를 이용해서 JobQueue를 처리해주고 있는데 이렇게 되면 쓰레드들이 Job을 처리하는 도중에 데이터가 곂쳐서 레이스컨디션상황이 발생하는지 궁금합니다. 만약 그렇게되면 lock을 사용해야할까요??
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
RegisterSend를 하나의 스레드만 수행하는 이유가 궁금합니다.
큐에서 데이터를 꺼내는 작업 자체가 여러 스레드가 동시에 들어가도 의미가 없거나 wsasend가 스레드 안전하지 않아서 그런건가요? recv도 그렇고 send도 그렇도 하나의 세션에 대한 본질적인 작업은 사실상 하나의 스레드만 수행할 수 있다고 이해하면 되는걸까요?(사실상 여러 스레드가 접근해도 실질적인 세션의 공유자원(버퍼 등등)에 대해 순차적으로 접근할 수 있으므로 )
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
-1리턴이 대부분입니다
최종적에서 Recv가 정상적으로 처리되는것보다 -1로 리턴되는경우가 대부분입니다. 코드를 다운받아서 해봐도 어떨때는 정상적으로 되다가 다시작동하면 -1이 리턴되길 반복합니다. 무엇이 문제일까요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
session의 생명주기 관련 질문입니다.
안녕하세요 Session#1 강의를 듣다가 질문드립니다. 1. Session의 생명주기를 정리해봤는데 선생님께서 의도하신 세션 생명주기와 일치하는지 질문드립니다. 2. RegisterRecv() 하여 REFCOUNT= 4; 가 되었을 때 다음 동작으로 bool IocpCore::Distpatch(uint32 timeoutMs) or void Listener::RegisterAccept(AcceptEvent * acceptEvent) 둘 중 어느 함수가 먼저 호출될지 상황마다 다른건지 궁금합니다. Dispatch 함수가 먼저 호출될 경우는 REFCOUNT =5 가 되었다가 RegisterAccept에서 세션 교체에 의해 다시 4가 될것이고 RegisterAccept 먼저 호출시에는 REFCOUNT가 3으로 먼저 깎일 수 있기 때문입니다. 3. 디버깅 해보니 AcceptEx나 WSARecv에서 Overlapped 인자로 이벤트 인자를 넘기는데, 이 이벤트 객체의 Reference 카운트가 GetQueuedCompletionStatus 함수에서 꺼내올 때 그대로 유지되는거 같은데 GetQueuedCompletionStatus 전에 누가 Reference 카운트를 1감소 시키면 1감소된 만큼 GetQueuedCompletionStatus 에서 복원될까요? ----------------------------------------------------------------------------------------- Listener::RegisterAccept() 함수 SessionRef session = _service->CreateSession(); //+1 REFCOUNT = 1 acceptEvent->session = session; //+1 REFCOUNT = 2 SessionRef session = _service->CreateSession(); Register Accept 리턴시 session 지역변수 소멸, -1 REFCOUNT = 1 ----------------------------------------------------------------------------------------- Listener::ProcessAccept() 함수 SessionRef session = acceptEvent->session; //+1 REFCOUNT = 2 ----------------------------------------------------------------------------------------- void Session::ProcessConnect() 함수 GetService()->AddSession(GetSessionRef()); // +1 REFCOUNT = 3 ----------------------------------------------------------------------------------------- void Session::RegisterRecv() 함수 _recvEvent.owner = shared_from_this(); // ADD_REF //+1 REFCOUNT = 4; ----------------------------------------------------------------------------------------- void Listener::RegisterAccept(AcceptEvent* acceptEvent) acceptEvent->session = session; // 세션 교체 REFCOUNT = 3; ----------------------------------------------------------------------------------------- Listener::ProcessAccept() 함수 SessionRef session = acceptEvent->session; // ProcessAccept 함수 소멸시 session 지역변수 소멸,-1 REFCOUNT = 2 ----------------------------------------------------------------------------------------- bool IocpCore::Dispatch(uint32 timeoutMs) IocpObjectRef iocpObject = iocpEvent->owner; // RegisterRecv IOCP 값으로 owner 가 session 일 경우 +1 REFCOUNT = 3 ----------------------------------------------------------------------------------------- void Session::ProcessRecv(int32 numOfBytes) _recvEvent.owner = nullptr; // RELEASE_REF ,-1 REFCOUNT = 2 if (numOfBytes == 0) 일경우 GetService()->ReleaseSession(GetSessionRef()); //-1 REFCOUNT = 1 ----------------------------------------------------------------------------------------- bool IocpCore::Dispatch(uint32 timeoutMs) IocpObjectRef iocpObject = iocpEvent->owner; // Dispatch 리턴시 iocpObject 지역 변수 소멸, -1 REFCOUNT = 0
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Atomic<uint32> _lockFlag의 load 함수 호출 시 읽기 액세스 위반
강사님 안녕하세요. 정말 좋은 강의 잘 듣고 있습니다 ㅎㅎ 감사합니다. 다름이 아니라 지금까지 저 스스로 코드를 써나가며 강의를 복기하고 있는데, 이번 시간 진도 이후로 갑자기 문제가 없었던 LockBased Memory Allocator 부분에 문제가 생겼습니다. 디버깅으로 함수 콜 스택을 추적해보니, Lock::WriteLock 함수에 쓰레드 자기 자신이 WRITE_LOCK을 가지고 있는지 확인하는 const uint32 lockThreadId = (_lockFlag.load() & WRITE_THREAD_MASK) >> 16; 에서 예외(읽기 액세스 위반)이 발생했고, 더 적은 쓰레드 환경(주 쓰레드 + 함수 실행 쓰레드 1개)에서도 예외가 발생했습니다. atomic header에서 _NODISCARD _TVal load() const noexcept { // load with sequential consistency const auto _Mem = _Atomic_address_as<int>(_Storage); auto _As_bytes = __iso_volatile_load32(_Mem); _Compiler_or_memory_barrier(); return reinterpret_cast<_TVal&>(_As_bytes); } _Mem이 0x18였다는 이유로 예외가 throw되었습니다. Atomic 타입의 멤버 변수로부터 오류가 생긴다는 거 부터가 당황스럽고, 구글링해도 결과가 안나오고,Stompallocator로도 추적이 안되어서, 디버깅 할 방법을 도저히 모르겠습니다. 이렇게 빌드도 잘되고 런타임에서 오류가 발생할 때, 강사님만의 노하우가 있으신가요? 더불어서 혹시 접해보신 오류라면 조금 도와주신다면 감사하겠습니다 ㅠㅠ 혹시 몰라서 함수 콜스택도 첨부합니다.
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
AcceptEx함수를 사용하지않고 WSAIoctl로 함수포인터를 받아 사용하는이유
안녕하세요 선생님 함수관련된건 문서를 보고 이해하면 된다고 하셨는데 MS문서와 블로그를 찾아봐도 명확하게 이해가 가지않아 질문드립니다. 제가 찾아본바로는 WSAIoctl함수는 AcceptEx함수와 다르게 dll을 이용하지않고 직접 함수를 호출한다는데... 이게 제가 이해한게 맞는건가요? 아니라면 AcceptEx함수를 사용하지않고 WSAIoctl를 이용하여 런타임에 함수포인터를 얻어와 사용하는 이유가 무엇인가요?
- 미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
SetUpdateAcceptSocket 질문입니다.
1. 일반 accept 함수가 리턴하면 client 소켓과 통신할 소켓이 리턴되는데 listen 소켓 속성과 같은 속성이 리턴된다고 알고있습니다. 하지만 AcceptEX 함수에서는 client와 통신할 소켓을 미리 만들어 인자로 전달하기 떄문에 수동으로 SetUpdateAcceptSocket 를 호출하는 것인가요? 2.getpeername 함수에서 두번째 인자로 reinterpret_cast<SOCKADDR*> 캐스팅을 해주는 이유가 궁금합니다. static_cast나 (SOCKADDR*) 과 같은 캐스팅보다 위와 같이 하는 이유가 궁금합니다. 3. AcceptEx 함수에 IocpEvent 형 acceptEvent를 Overlapped 타입으로 캐스팅하여 전달하는데 OVERLAPPED 구조체를 상속하여 크기가 큰 클래스(IocpEvent)를 전달하여도 OVERLAPPED 타입에 맞게 데이터가 잘리지 않고 GetQueuedCompletionStatus에서 복원는데 이게 맞는건가요? 포인터로 주소만 전달하기 때문에 가능한 것인지 int -> char 타입으로 캐스팅 할때처럼 데이터가 잘리지 않는건지 궁금합니다