월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
패킷 관련 질문이 있습니다!
패킷 보내시는 부분을 보고 있는데 쪼개서 보낼 때 결국엔 그 정해진 길이에 맞춰서 여러번 보내게 될텐데(예시: 1024 바이트를 최대로 하여 보냄)그렇게 되면 데이터가 채워져있는 부분을 제외하고 나머지는 0 바이트로 채워져서 보내지는걸로 알고 있습니다.근데 이게 가끔씩은 패킷에서의 데이터 자체가 0 바이트인 경우도 있을거같은데 이런 경우는 어떻게 판별해주는 방법이 따로 존재할까요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
OnRecvCompleted 내 RegisterRecv를 다시하는 이유가 먼가요?
좋은 강의 우선 너무 감사드립니다. ㅜㅜ 23:34 이후 부터 Recv 관련 내용을 듣다가 궁금한 부분이 있어서 질문드립니다. (1)OnAcceptHandler의 전체 코드를 살펴보면 클라이언트와 접속이 된 이후 수신 / 송신 이후 클라와의 연결을 끊어버리는데 (session.Disconnect() -> Shutdown, Close), OnRecvCompleted 내 RegisterRecv를 다시하더라도 클라쪽에서 보내는 데이터를 미처 다 수신받기 전에 끊겨질수 있지 않나요? 서버가 클라와의 연결을 끊을려고 할때 (Shutdown, Close) 클라쪽에서 보낸 데이터가 남아 있을 경우 바로 끊지 않고 비동기 수신 함수로 등록된 결과를 모두 처리하고 끊는걸로 이해하면 될까요? (2) 다시 낚시대를 던지는 행위 ? 가 결국은 클라와 연결이 된 이후클라쪽에서 한번에 여러개의 패킷을 send를 하기 때문으로 이해가 되는데, 만약 클라가 연결이 된 이후 한 개의 패킷만 전달한다는 정책이라면 따로 OnRecvCompleted 내 RegisterRecv를 하지 않아도 될까요?
- 해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
몇 가지 질문이 있습니다!
안녕하세요, 루키스님.좋은 강의를 제공해주신 것에 대해 항상 감사드립니다.기존에는 서버의 코어 부분은 건드리지 않고 컨텐츠 부분만 직접 수정 및 추가하며 클라이언트와 연동해보는 사이드 프로젝트만 진행해보았고,서버 코어 부분에 대하여 좀 더 깊게 이해를 해보기 위해 다시 정주행을 하는 중 입니다.이유는 모르겠지만, 같은 내용의 강의를 계속해서 볼 때마다 점점 이해되는 범위가 달라지는 것이 느껴지는 것 같긴 하네요..이번에는 최대한 운영체제 같은 윗 분들의 사정(?)을 고려해보며 이해를 해보며 접근을 해보려고 하는데요.그러다 보니 몇 가지 의문점이 생겨 질문 드립니다. 1. 세션코드에서 Send부분에 lock안에서 enqueue를 하는 이유는 TCP 통신의 순서를 보장하기 위해서 인가요? 2. Recv부분은 왜 lock이 안걸려있는지 이해가 되지 않습니다.검색해보거나 다른 분들 질문을 참고해보면, ReceiveAsync 부분이 1개의 스레드만 접근하는 것을 보장하기 때문이라고 하시는 것 같은데요.이 부분은 소켓API 부분에서 보장해주는 건가요?그렇다면 다른 SendAsync와 같은 부분과 다르게 버퍼를 읽던 중 다른 수신을 받게 되어도, 수신을 처리하는 스레드가 스레드풀에서 제공되는 것이 아닌, 현재 수신을 처리 중인 스레드가 완료 될 때 까지 어딘가에서 대기하고 있다가 한 번에 처리되는 건가요? 3. PacketSession의 OnRecv 부분에서 BitConverter.ToUInt16 메서드가 메서드 자체적으로 바이트 배열의 시작하는 인덱스에서 '2바이트'만큼을 부호없는 정수로 바꾸는 메서드라고 알아보았는데요.메서드 자체에서 '2바이트'라고 지정해둔 것은 보편적으로 패킷의 크기를 나타내는 헤더를 2바이트로 정하기 때문인가요? 4. 위처럼 OnRecv에서 패킷이 온전하게 도착하지 않았을 때, 단순히 writePos만 옮겨진 상태로 다음 패킷을 받을 때까지 기다리기만 해도 되는 것은, TCP 통신 자체가 '순서를 보장하기 때문에 앞에서 온전하게 받지 못한 패킷에 대해서 다른 패킷보다 먼저 다시 보내주고', '온전하게 도착하지 않은 부분에 대해서만 보내주기 때문'일까요?그리고 그렇다면 위처럼 순서를 보장해주고, 상대가 어디까지 받았는지, 어디를 못 받았는지 판단하는 것은 운영체제에서 알아서 처리되는 건가요?만약 상대가 못 받았을 경우 다시 보내줘야 한다면, 커널에서 패킷을 송신한 뒤에도 상대가 온전하게 받았다고 신호하기 전까지는 커널 상의 버퍼에 해당 패킷을 계속 저장해두고 있으려나요? 5. ArraySegment를 사용할 때, Array를 통해 배열의 시작 위치를 넘기고 어떤 위치부터 조회할 지(?) 조회할 위치를 넘기는 부분이 Offset인 것 같은데요.Offset을 0으로 두고 readPos및 writePos나 DataSize, FreeSize 등을 통해 패킷 시작 위치나 범위를 지정해주는 것은 Offset 값을 변경하며 이를 컨트롤 하는 것이 복잡하기 때문인가요? 처음 강의를 수강할 때에 비하면 강의 내용이 점점 머릿속에 그려지고 구조와 흐름이 얼추 잡혀가는 느낌이지만,누군가가 "너 한 번 혼자서 서버 만들어봐!!"라고 한다면 강의를 참고하거나 구글링 없이 혼자 서버 코어 단을 만들 수 있을 거라는 엄두가 나질 않는데요.6. 4년제 학부 졸업생의 수준에서 서버 코드를 보고 이 부분은 왜 이렇게 작성된 것인지, 어떤 흐름으로 코드가 실행되는지 정도만 이해하면 게임 서버 프로그래머로 취업하기엔 충분할까요...?아니면 정말 혼자 서버 코어 부분을 작성할 수 있을 정도가 되어야 하는건가요? 강의 들으며 궁금했던 부분을 싹 모아서 정리해보니 장문의 질문이 되어버렸네요 죄송합니다 ㅠㅠ다시 한 번 좋은 강의 제공해주셔서 정말 감사합니다.
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
서버 OnAcceptCompleted, 클라이언트 OnConnectCompleted 함수의 Start()
Lister 클래스Session session = sessionFactory.Invoke(); session.Start(args.AcceptSocket); // ★ Connector 클래스Session session = _sessionFactory.Invoke(); session.Start(args.ConnectSocket); // ★ 1)args.AcceptSocket args.ConnectSocketStart 함수의 매개변수 둘 다 클라이언트 소켓이 맞나요??
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
WriteLock이 Empty_Flag일때만 가능하다면...
a스레드에서 ReadLock 사용하고b스레드에서 WriteLock을 사용하면 대기가 되는데(Empty_Flag가 아니니깐)ReadLock은 Write_Mask만 없으면 계속 들어올 수 있으니끝임없이 ReadLock이 발생된다면 대기 중인 b스레드는 언제 WriteLock이 진행되나요?
- 해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
JobQueue는 무조건 싱글스레드 환경에서 돌아가게 구현하나요?
JobQueue에 쌓인 일감이 만약 극단적으로 많거나 작업 하나하나의 비용이 크다면 병목현상이 일어나지 않을까하는 의문이 생겼습니다.JobQueue 내에서도 겹치지 않는 작업은 멀티스레딩으로 처리하여 최적화하는게 과연 효율이 나올지, 또 실제 현업에서 이렇게 적용하여 사용하는지 궁금합니다!
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
단일 스레드로 처리할 경우 속도 문제점 있나요?
GameRoom을 하나의 스레드로 jobqueue를 사용해서 공유자원을 관리 하면 lock에서는 자유롭지만 하나의 스레드인 만큼 많은 처리를 해야할 경우 딜레이가 생길수도 있을거라고 생각하는데 lock을 타이트하게 거는 방법보다 하나의 스레드에서 처리하는게 속도가 더 빠른가요?하나의 스레드로 룸을 관리하니 결국 작업을 하나씩처리에 따른 속도 이슈가 없는지 궁굼합니다. 예를들어 갑자기 수많은 이용자가 들어와 엔터패킷을 탄다면 디비도 접근해야될때 이에 따른 실시간 처리 성능이 보장되는지 궁굽합니다.
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
원자성
안녕하세요.처음 interlocked 없이 for문을 10,000회로 두고number를 ++하거나 --했을 때 0 이 잘 출력됐는데,이 땐 그냥 반복 횟수가 적어서 원자성 문제가 발생되지 않았던 건가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
6:00
릴리즈 모드로 해도 디버그 모드랑 동일하게 출력되는데 뭐가 문제인가요? using System.Threading;namespace ServerCore{ internal class Program { // 전역이기 때문에 쓰레드들이 동시에 접근 가능 static bool _stop = false; static void ThreadMain() { Console.WriteLine("쓰레드 시작!"); while(_stop == false) { // 누군가가 stop 신호를 해주기를 기다린다 } Console.WriteLine("쓰레드 종료!"); } static void Main(string[] args) { // Thread t = new Thread(ThreadMain); Task tt = new Task(ThreadMain); tt.Start(); // 1초 존야 후 다시 실행 Thread.Sleep(1000); _stop = true; Console.WriteLine("stop 호출"); Console.WriteLine("종료 대기중"); tt.Wait(); // t.Join(); 과 동일 Console.WriteLine("종료 성공"); } }
- 해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ReaderWriterLock은 반드시 재귀적으로 호출되어야 하나요?
만약 한 쓰레드에서 ReadLock과 WriteLock이 전부 호출된다고 했을 때 반드시 호출의 역순으로 Unlock을 호출해야 되나요? 아래는 C#에 구현돼있는 ReaderWriterLockSlim 클래스를 사용하여 실행한 예시입니다.class Program { static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); static void Main(string[] args) { Task.WaitAll( Task.Run(() => { _lock.EnterWriteLock(); _lock.EnterReadLock(); Thread.Sleep(5000); _lock.ExitWriteLock(); _lock.ExitReadLock(); })); } }WriteLock -> ReadLock -> WriteUnlock -> ReadUnlock 순으로 호출했고 정상적으로 작동합니다.강의에서 구현한 ReaderWriterLock을 사용해도 예외가 발생하지는 않습니다만 위의 순서로 호출하면 flag가 엉망이 됩니다.public void WriteUnlock() { int lockCount = --_writeCount; if (lockCount == 0) Interlocked.Exchange(ref _flag, EMPTY_FLAG); }동일한 쓰레드가 ReadUnlock을 호출하지 않은 상태에서(즉 read count가 0이 아닌 상태에서) WriteUnlock을 호출할 경우 flag가 0으로 초기화되기 때문에 이후에 ReadUnlock을 호출할 경우 flag가 -1로 초기화됩니다. 제가 생각하기엔 굉장히 특이한 케이스고 실제로 함수가 재귀적으로 호출되기 때문에 발생할 일은 없다고 보는데요...혹시라도 휴먼에러로 위와 같은 상황이 벌어질 경우를 대비해서 예외를 추가하거나 WriteUnlock 로직을 수정해서 'EMPTY_FLAG'가 아닌 '_flag & READ_MASK'를 대입하면 어떤가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Mac OS 쓰레드풀 사용 문제 질문드립니다. (11:12)
위쪽에도 같은 맥북 질문이 있는것으로 확인 하였는데 해결방법을 모르겠어서 질문드립니다. 쓰레드가 Console.WriteLine까지는 진입을 하지만 출력이 되지는 않는 문제가 발생합니다.또한 중간에 쓰레드가 전부 사라져버리고 디버깅이 더이상 진행되지 않는 문제가 발생합니다.
- 해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
PacketSession에서 buffer.Count와 dataSize의 비교
안녕하세요 PacketSession에서 if (buffer.Count < dataSize) break;이 부분의 코드가 왜 필요한지에 대해서 의문이 생겨 질물 남깁니다 예를들어 100바이트 크기의 버퍼가 OnRecv매개변수로 들어왔고 해당 100 바이트가 5가지 패킷의 정보를 들고 있다고 했을 때하나의 패킷을 처리할 때 마다 해당 크기의 dataSize만큼 buffer크기(Count)가 갱신 될텐데 그렇게 된다면 위의 조건에는 들어오게 될 일이 전혀 없게 되는거 아닌가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
System.InvalidOperationException 이러한 오류가 나옵니다.
System.InvalidOperationException: 'The ThreadLocal object is not tracking values. To use the Values property, use a ThreadLocal constructor that accepts the trackAllValues parameter and set the parameter to true.' 코드를 작성했는데 이러한 오류가 나옵니다.제가 작성한 코드에 오타를 뒤져봐도 찾을 수가 없습니다.혹시 어떠한 경우에 이런 오류가 생기나요 100% 로 오류가 나옵니다.public static ThreadLocal<SendBuffer> CurrentBuffer = new ThreadLocal<SendBuffer>( () => { return new SendBuffer(ChunkSize); }, trackAllValues: true); 찾아보니 스레드 로컬 커런트 버퍼를 만들 때 이렇게 해주면 오류가 사라지긴 합니다.왜 이런 문제가 발생하는 건가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
소캣 통신 데이터 유실 궁굽합니다!
안녕하십니까. 강의너무잘 듣고있습니다. 서버를 공부하면서 데이터가 유실되면 어떤 방식으로 진행해야하는지 궁굼해서 문의드립니다.tcp/ip특성상 안전성이 높아서 유실이 안되는 걸로 알고있는데 유실될 가능 성도있나요?데이터 유실이된다면 어떻게 처리해야하나요?데이터 유실이 실무에서도 일어나나요?일반적으로 데이터 유실이란게 tcp/ip에서 데이터가 끊어져서 들어오는걸 말하는 건가요? 만약 데이터 유실처리 방법으로 유실 유무를 판단하여 다시 서버에서 요청을 하는 로직을 만든다면 일반적으로 재전송 패킷을 따로만드나요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
안전한 게임 개발
안녕하세요. 루키스님의 강의를 듣고 멀티플레이 게임을 만들어보려고 하는데, 어디서부터 어디까지는 서버가 처리하고 나머지는 클라이언트가 처리해야 할지 고민이 됩니다. 서버에 침투할 수 있는 핵을 최대한 막을 수 있는 안전한 상황을 구축하고 싶습니다... 그리고 서버와 클라이언트는 동시에 개발하는 게 좋을까요 아니면 클라이언트를 전부 개발 후 서버를 개발하는 게 좋을까요? 감사합니다.
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
send 와 recv 관련하여 질문이 있습니다!
클라입장에서 Connect를 통해 연결을하고 연결된 소켓에 Send를 하게되면 서버입장에서 Recv하게되는부분에서 1.public void Start(Socket socket){ _socket = socket; _recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted); _recvArgs.SetBuffer(new byte[1024], 0, 1024); _sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted); RegisterRecv();}이부분에서 RegisterRecv를 하나만 써 준 것이 낚싯대에 비유하여 접근을 하고있을시 다른쪽에서 접근을 못한다고 하셨는데. 이게 구조적으로 그렇게 짜여진 것인가요??+ 또 RegisterRecv() 이것을 여러게 써주면 lock을 걸어야 하는건가요 ?? 2.그리고 OnSendCompleted 에도 lock을 건 이유가_sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);이 부분에서 중복해서 들어오는 것을 방지하기 위해 거셨다고 하셨습니다. 그럼 Recv의_recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted);이 부분은 어떻게 다른건가요?? 이 부분은 제 나름대로 이해하려고 예를 든 부분입니다. 제대로 이해했는지 봐주시면 감사합니다!Send와 Recv를 게임의 1:1 채팅에 적용하면 A유저와 B 유저가 1:1 채팅을 하고있는 중에 A유저가 채팅을 보내면 클라에서 Send를 하고 서버에서 Recv를 해 받고 그걸 서버 Send를 통해 B유저 클라에 보내준다 (이 부분에서 서버 Send는 1:1하고있는 B에만 가야하니까 lock을 검 : 또 다른 유저(클라)가 보낸 채팅? 들이 섞이지않게... )
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Listener 수업부분 질문입니다!
코드 실행하면 이런식으로 브레이크포인트가 잡히는데 왜 이런거 일까요 .. 밑줄도 많이생기고 해서 질문남깁니다!
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
EventHandler<T> 를 사용하는 이유가 무엇인가요?
Listener 클래스에 args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted); 부분을 args.Completed += OnAcceptCompleted; 이렇게 바꾸어도 문제가 생기지 않는데 왜 EventHandler<T> 를 사용하는 것인가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
RecvBuffer 질문
안녕하세요. Session에서 _recvArgs.SetBuffer() 하는 부분에서 궁금증이 생겼습니다. _recvBuffer.WriteSegment는 다음에 올 패킷 사이즈가 어느 정도인지 모르니버퍼의 offset + writePos부터 여유공간 끝까지(FreeSize)를 뭉탱이로 가리켜서 주는걸로 이해했습니다.그리고 _recvArgs는 WriteSegment가 가리키는 공간을 자신의 버퍼로 사용합니다. 만약, 실제로 보내고자 했던 패킷의 사이즈가 10인데, _recvArgs의 FreeSize가 5라면,소켓은 일단 5만큼만 버퍼에 넣은 다음에 버리고, 나머지 5만큼의 재전송을 요청하는 건가요?아니면 아예 버리고 재전송을 요청하는건가요?그것도 아니라면 물밑(하위 레이어)에서 버퍼가 꽉 찼다는 신호를 서로 주고받아서 혼잡(?)이라 판단하고 애초에 보내지 않고 기다리는건가요? (버퍼가 비어지길 기다리다가 지치면 Disconnect 혹은 Loss?) 그리고 RecvBuffer의 Buffer가TCP 이론을 배울 때 말하는 window size와 직접적으로 연관되는 건가요?아니면 소켓 별도의 버퍼가 또 따로 있는건가요?
- 미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Unity 연동 시 Disconnect 문제
안녕하세요 강사님코드비교도 하고 소스코드를 다운 받아서 시도를 해도 해결이 되지 않아 문의 드립니다.유니티 2022.3.15f 버전을 사용하고 net8.0을 이용하여 서버 및 클라이언트 빌드를 했습니다.유니티 연동까지 했고, 버퍼크기는 65535로 설정해두었습니다.유니티 connector.cs에서 클라이언트를 1로 설정했을 때에는 문제가 없으나2 이상 올릴 경우 1번이 무조건 disconnect 처리가 됩니다. 100이상 올릴 경우 중간에 패킷조립에 실패하여서버가 종료됩니다. 며칠을 고민하고 코드를 비교하고 강사님의 코드로만 진행을 해도 똑같아 문의남깁니다.