묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
서버 중지 기능
안녕하세요. 서버를 중지하고자 하면 어떤 절차를 거쳐야 하나요? Listener
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
DB에서 플레이어 정보를 긁어오는 부분에 대한 질문입니다!
안녕하세요!16:02에서 플레이? 플레이어 정보를 DB에서 긁어온다고 하셨는데요. DB에서 특정 유저의 정보를 가져오려면 unique id, id+password 조합이든, 식별 값이 필요할 거라 생각합니다. 이는 DummyClient OnConnected()에서 C_LOGIN 패킷을 만들 때 함께 보내줘도 될까요? 만약 그렇다면,로그인은 웹 등의 게임 외부 환경에서 먼저 진행될텐데, 웹 등의 외부 환경에서 로그인 성공 이후 게임 파일을 실행할 때 id, password(해싱된 값)를 같이 넘겨주고 그 정보로 Handle_C_LOGIN에서 해당 유저의 정보를 가져오면 되는 걸까요?제가 C# 강의 해당 강의까지는 들을 여력이 안 돼서, 여쭙습니다. C# 클라 <-> C++ 서버 헤딩할 때 적지 않은 시간이 쓰일 거 같아, 구현하지 않는 부분에 대해서는 흐름이라도 명확하게 가져가려고 합니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Protobuf Packet 클라이언트 - 서버 설계
서버에서 Protobuf를 사용하고클라이언트에서 예기치 못한 이유로 사용하지 못했을 때주고 받는 Packet.id그리고 그 id에 해당하는 정보(구조체)가 같다면상관 없을 까요?ex)서버 -> S_CHAT : string msg; 구글 프로토버프로 만듬클라이언트 -> S_CHAT : string msg: 일반 구조체로 만듬
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
iocp 내부 동작 관련 질문
Windows IOCP(I/O Completion Port) 모델을 사용하여 서버를 개발하고 있으며, WSASend 호출의 처리 순서에 대해 명확히 알고 싶습니다.1. WSASend 호출 순서 보장 - 서버에서 연속적으로 WSASend를 3번 호출할 경우, Windows 내부에서 정확히 호출된 순서대로 처리되는지? - TCP의 순서 보장과는 별개로, IOCP 모델 자체의 내부 처리 순서는 어떻게 되는지?2. 클라이언트 측 완료 통지 순서 - 서버에서 WSASend를 3번 호출했을 때, 클라이언트가 GetQueuedCompletionStatus(GQCS) 함수를 호출하면 서버의 호출 순서와 동일한 순서로 완료 통지가 수신되는지?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
채팅실습 과정에서 Protocol.pb.h error
채팅실습을 시작해서 BufferData 구조체를 삭제하고빌드를 하게 되면 파일은 복사가 되어서 다른 패킷아이디들이 생성되는데지웠던 BufferData가 계속해서 BufferData가 없다는 에러가 발생하고실제로 Protocol.pb.h에 남아있는 현상이 발견됩니다..이런 증상 겪으신분 있으실까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
보편참조 관련 질문
강의 내용 22:00에 보편참조라고 설명해 주시면서Job 생성자를 만들어주셨습니다.하지만 Job생성자는 우측값 참조가 아니면 생성이 되지 않습니다.반면에 우측값 참조로 넣어주면 전부 에러 없이 생성되었습니다Job 생성자가 보편참조라면 좌측값인 player로도 생성이 되어야 하지 않나요? 만약 Job 생성자가 보편참조가 아니라면GRoom->PushJob(&Room::Enter, player) 부분에서보편참조가 아닌 함수에서 L-value를 std::forward를 사용하면 오른쪽 참조값으로 바뀌기 때문에 auto job = ObjectPool<Job>::MakeShared(owner, memFunc, std::forward<Args>(args)...);이함수는 결국 우측값 참조를 받는 Job생성자를 호출하게 되어 Job을 만들어 주었기 때문에 에러가 발생하지 않고 잘 실행 되었던거라고 이해하면 될까요? 만약 Job생성자가 보편참조가 아니라면 왜 보편참조가 될 수 없나요? 강의 핵심내용은 JobQueue에 관한 내용이지만보편참조가 너무 헷갈려서 질문하게 되었습니다..
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
boost asio 강의
안녕하세요 루키스님혹시 작년에 진행했던 javawork 님의 boost asio 강의는인프런에 판매하실 생각은 없으신 건가요??
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
OnDisconnected() 부근에서 _players.clear() 의문점이 있습니다.
06:05 부근 질문입니다.클라이언트가 캐릭터 선택과 동시에 연결이 종료될 때 서버가 혼잡하다면, Handle_C_ENTER_GAME()과 OnDisconnect()가 동시에 일어날 수 있다고 생각되는데요.. 그렇다면 멀티 스레드에서 _players에 동시 접근하는 일이 발생하지 않나요?그렇게 된다면, _players.clear() 이후 _players[index] 접근하는 문제로 서버가 튕길 거라고 생각했습니다.지금까지는 그러한 오류가 터진 적이 없었는데, 테스트가 부족했던 것인지 아니면 잘못 생각하고 있는 것인지 알고 싶습니다.
-
해결됨[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
CPU를 과도하게 점유하면서 멈추는 현상
안녕하세요 쓰레드 배분 강의 소스 코드부터 현재 강의까지, 서버가 정상적으로 동작하지 않는 현상이 있어 확인 요청드립니다.DBThreadJob 메서드에서 _executeQueue가 비어 있을 때 루프가 무한히 반복되면서 CPU를 과도하게 점유하는 문제가 있는 것 같습니다. 저는 macOS에서 서버를 실행 중인데, Windows와의 CPU 스케줄링 차이로 인해 발생하는 문제로 추측됩니다. 확인해주시면 감사하겠습니다!
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
TCP 통신 데이터경계
안녕하세요.TCP 통신에서 전송 순서와 패킷 손실을 보장해준다고 할 때,보내는 데이터가 서버의 수신 버퍼 크기를 초과할 경우, 이전에 받은 데이터와 다음에 받는 데이터를 합쳐서 원하는 형태로 처리하게 되는 걸까요?예를 들어, 서버의 수신 버퍼가 5바이트일 때,1차 수신 데이터가 "L5AAA"이고2차 수신 데이터가 "AA"라면,"L5"는 데이터의 길이가 5라는 뜻이면, 이 경우 데이터가 부족하면 다음 수신 데이터를 기다려 "L5AAAAA" 형태로 합쳐 처리하는게 맞을까요?
-
미해결[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + T2)
첫 강의 manager 가 재생이 안됩니다.
첫 강의 manager 가 재생이 안됩니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
환경설정 20:20초 빌드 시
빌드 시 링크 에러 2개가 나옵니다.강의 따라서 잘 타이핑 하고 따라왔는데..이 두개의 오류가 나오면서 빌드 실패를 합니다.왜 그런걸까요?
-
미해결[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + T2)
T2는 어떻게된걸까요?
T2가 지금 멈춰있는것같은데..어떻게 진행 되는걸까요?ㅜㅜ
-
미해결[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + T2)
9주차 강의 'Stage 분할' 이 로딩만 뜨고 재생되지 않습니다
전후 강의 동영상은 정상적으로 재생이 되는데, 이 강의는 로딩만 계속되고 화면이 나오지 않네요. 혹시 제가 뭐 세팅을 변경해야 하는 것이 있으면 알려주시기 바랍니다.맥/윈도우 크롬 브라우저를 이용해서 수강 중입니다.가능하다면 빠른 해결이 되었으면 합니다.
-
미해결[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + T2)
강의 완료 시기
강의 완료시기가 언제쯤인지 알 수 있을까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
다른 스레드가 write하고 있을 때 readlock 허용하나요?
ReadLock 코드uint32 expected = (_lockFlag.load() & READ_THREAD_MASK); if (_lockFlag.compare_exchange_strong(OUT expected, expected + 1)) return;WriteLock 코드const uint32 desired = ((LThreadId << 16) & WRITE_THREAD_MASK); ... uint32 expected = EMPTY_FLAG; if (_lockFlag.compare_exchange_strong(OUT expected, desired)) { _writeCount++; return; }Write할 때 lockFlag를 LThreadId << 16로 저장하기 때문에 첫 비트 ~ 15비트까지는 0으로 초기화가 될것입니다.ReadLock에서는 Read용 Mask를 쓰는데 그럼 Write에서 초기화해준 lockFlag를 볼 수 없어서 항상 참값이 나와 expected + 1로 수정되는거 아닌가요?? 다른 스레드가 Write하고 있을 때 Read를 허용하는것인지 궁금합니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Protobuf 사용시 Lnk2001 에러 두줄
이 두줄을 이틀째 해결 못하고있습니다.3.17.0 ~ 3.19.x 버전은 빌드 O5.27.0 ~ 5.28.x 버전은 빌드 X 최신 버전 및 그 근처 버전들은 전부 마지막에 저 두 에러가 떠서 결국 잠시 내려놓고 다른 방법을 찾아봤습니다.공식문서를 참고해 vcpkg에서 가장 최신버전을 설치해보니 4.25.1로 빌드되고 니 프로젝트가 문제 없이 빌드 되는것 확인했습니다. 최신버전 한 번 사용해보겠다고 이것저것 시도한건 다 실패한건 아쉽지만 그래도 안전하게 사용하가능한 여러 버전을 알게 됐네요.vcpkg에서 설치하면 .lib이나 google을 안넣어도 자동으로 적용되는데 문제 없을까요?아니면 안전하게 설치되는 버전을 파악했으니 삭제하고Cmake로 해당 버전을 다시 빌드할까요?그리고 최신 버전은 꼭 사용할 필요 없는 거겠죠?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
오류 원인을 찾기가 어렵네요.
안녕하세요.거의 하루종일 보고 있는 문젠데요.클라이언트에서 에코해줄 때 강사님은 OnRecvCompleted() 함수 안에서 인자로 받은 length가 아니라 sizeof send_buffer를 사용하고 계셔서 오류가 발생 안 했어요.인자로 받는 length를 해주면 프로그램 구동하고 나서 얼마 안돼서 주고받는 데이터가 영원히 증가합니다. 물론 ASSERT_CRASH가 있기 때문에 메모리 할당해주는 부분에서 결국 멈추긴 합니다.정확한 이유를 못 찾겠네요. 이리저리 중단점 찍어보는데, 한 가지 확실한 건 서버에서 WSASend() 해주고 클라에서 받을 때 갑자기 데이터 사이즈가 튑니다. 더미 클라에서 세션을 하나만 넣어줘도 재현돼요.이럴 때 비동기 + 멀티스레드는 정말 헬이네요. ProcessSend()로 들어오는 sendBytes가 갑자기 26, 52..이렇게 되어버립니다. GSendBufferManager에서 반환하는 메모리 위치는 문제가 없어요. 어느 순간 데이터를 미친 듯이 이어 붙입니다.위 이미지처럼 하나씩만 오고 가야 하는데(Hell, World!)어느 순간 아래 이미지처럼 확 늘어납니다.계속 누적돼요. 강사님 코드 거의 그대로입니다.WSASend() 동작이 중첩됐나까지 의심하게 되네요. 그러나 송신 큐 부분에 락 걸고 이후 코드는 스택 변수라 강사님과 동일하게 진행됩니다.void Session::RegisterSend() { _send_event.Init(); _send_event.owner = shared_from_this(); // 보낼 데이터를 send_event에 등록 // 레퍼런스 카운트 유지를 위해 SendEvent의 멤버변수를 이용한다 { WRITE_LOCK; while (false == _send_queue.empty()) { SharedSendBuffer send_buffer = _send_queue.front(); _send_queue.pop(); _send_event.send_buffers.push_back(send_buffer); } } xvector<WSABUF> wsabufs; wsabufs.reserve(_send_event.send_buffers.size()); for (SharedSendBuffer send_buffer : _send_event.send_buffers) { WSABUF wsabuf; wsabuf.buf = reinterpret_cast<char*>(send_buffer->Buffer()); wsabuf.len = static_cast<LONG>(send_buffer->WriteSize()); printf("wsabuf len: %d\n", wsabuf.len); wsabufs.push_back(wsabuf); } DWORD send_bytes = 0; int32 result = WSASend(_socket, wsabufs.data(), static_cast<DWORD>(wsabufs.size()), &send_bytes, 0, &_send_event, nullptr); int32 error = WSAGetLastError(); if (SOCKET_ERROR == result && error != WSA_IO_PENDING) { HandleError(error); // release ref _send_event.owner = nullptr; _send_event.send_buffers.clear(); _send_registered.store(false); return; } } 정상적인 에코 서버라면 주고 받는 데이터의 크기가 계속 일정해야 한다고 생각해서 테스트한 건데 고통의 시간을 겪고 있습니다..참고로 GameSession에서 OnRecv 재정의할 때 1회만 브로드캐스트 해주고 있습니다.int32 GameSession::OnRecvCompleted(BYTE* buffer, int32 length) { // temp echo printf("GameSession OnRecvCompleted len: %d\n", length); SharedSendBuffer send_buffer = g_send_buffer_manager->Open(4096); memcpy(send_buffer->Buffer(), buffer, length); send_buffer->Close(length); g_session_manager.Broadcast(send_buffer); return length; }
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Session #1에서 owner를 이용한 레퍼런스 관련한 부분 질문입니다.
몇 년 전에 강의를 들었을 때 느꼈던 거랑 요새 다시 들으면서 느끼는 게 많이 다르네요. 새삼 코드 퀄리티가 너무 좋습니다. 감사합니다.레퍼런스 카운트 관련해서 궁금한 점이 있습니다. Session 객체는 Service의 sessions에서 관리하는 한, 비동기 IO 작업 중에 메모리가 해제될 일은 없을 거라고 생각되는데요.그럼에도 불구하고 이벤트 객체에 owner 객체를 둬서 레퍼런스 카운트를 1을 올려놓은 채로 작업을 진행하는 건 정말 혹시 모를 상황에 대한 대비일까요?연결이 끊어져야 sessions에서 세션 객체를 꺼내니까(~Session 소멸자 호출 확인) 웬만한 상황에서는 비동기 IO 중에 세션 객체가 날아갈 일은 없을 것 같단 생각이 들었습니다. 만약 그 상황에 대한 대비라면 지금 구조에서는 ProcessRecv가 시작하자마 nullptr으로 밀어버리는 것도 RegisterRecv()를 호출하기 직전으로 옮겨야 하지 않나 하는 생각도 들었습니다. 고견을 듣고 싶습니다!감사합니다!
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
template function과 inline 키워드 관련 문법질문
클래스 몸체(body)밖에 템플릿함수의 구현부를 작성할 때는 inline키워드를 사용하고몸채내부에는 사용하지 않고 있어서 궁굼해서 해당 내용을 찾아봤습니다. inline 키워드를 사용하는 이유는 ORD(one definition rule) 그니깐 중복정의를 막기위해서 사용합니다. 2. 쓸 때 없는 스택생성을 막아 오버헤드 최적화하지만 굳이 inline 키워드를 붙여주지 않더라도 컴파일러가 알아서 처리해주고inline키워드를 붙이더라도 컴파일러가 상황에 따라서는 적용시키지도 않기 때문에 inline 키워드는 쓰지 않아도 된다고 결과를 얻었는데 맞는걸까요?