작성
·
383
0
1. PackatQueue를 OnRecvcallback을 통해 거치게되면 유니티에서 사용되는 메인쓰레드로 사용할 수 있다는 얘기로 들리는데. 유니티에서 그렇게 작동하도록 만든것인가요?
즉 유니티 오브젝트와 서버를 연동시키려면 쓰레드는 무조건 큐(Push,Pop)를 거쳐서 와야한다? 라고 유니티 측에서 규칙을 정해둔거?
그리고
2. 전 강의에서 설명하셨을 수도 있는데 너무 많은게 지나가서 질문 드립니다... HandlePacket만으론 유니티와의 연동이 되지않은 걸로 보이는데 HandlePacket을 자동화해서 사용하는 이유가 있나요. 제가 이해한 바로는 1번에 해당하는 경우에만 유니티가 제대로 작동되는 걸로 보여져 HandlePacket은 뭘하는지 잘 모르겠습니다.
3. 기존에는 (유니티 연동 전) 백그라운드 풀에서 쓰레드를 뽑아와서 쓴다고 하셨는데.. 이 부분은 제가 잊은건지 모르겠지만.. 쓰레드 풀 자체를 어디서 생성해줬는지 기억이 가물가물합니다...
분명 첫수업시간 때 Task를 이용해 쓰레드 풀을 만드는 건 어렴풋이 기억이 나는데 그런 코드는 여기서 작성한 기억은 없고... 쓰레드 자체가 어디에서 왔는가에 대해 알려주실 수 있나요.. 메모하면서 진행해왔는데 찾기가 어렵네요.
4. 그리고 복습하는 도중에 알려주신 모든 부분을 응용해서 학습할 수 있게 해주신점 감사드립니다. 그런데 한가지 ThreadLocal을 이용한 최적화는 파이널 프로젝트에 응용한게 없는듯한데 파트 7정도 때에나 이런 것들을 한꺼번에 볼 수있을까요.
감사합니다.
---------------------------------------------------
답변 1
5
1.
[게임 로직은 반드시 메인 쓰레드(게임 쓰레드)에서 실행되어야 한다]는 규칙만 유니티에서 정해둔 것이고,
세부적인 구현 방법은 우리의 자유입니다.
우리가 그냥 아무 위화감 없이 사용하던 모든 C# 코드들은
다 유니티 게임 쓰레드에서 실행되고 있었기 때문에,
이것에 대해 고민을 할 필요가 없었습니다.
그런데 네트워크 비동기 AsyncSend/AsyncRecv를 호출하면,
완료 통지 Handler함수가 다른 쓰레드에서 실행이 되니 문제가 발생합니다.
이 쓰레드는 게임 쓰레드가 아니기 때문에 여기서 유니티와 연관된 코드에 접근해서 뭘 하려고 나면 바로 에러가 납니다.
따라서 네트워크 Handler 쓰레드에서는 직접적으로 게임 로직을 실행하지 않고,
특정 네트워크 메시지가 왔다는 사실을 기록하기 위해
Packet class로 만든 다음에 이를 Queue에다가 넣기만 합니다.
결국 한참 지나서 게임 쓰레드에서 여유가 될 때 꺼내서 처리하는 방식으로 진행이 되겠죠.
CEO 비서실에 매우 중요한 업무 내용을 전화로 알려주면,
그것을 비서가 마음대로 처리하지 않고
전화 내용을 메모지에 적어 CEO 책상에 올려놓고
나중에 CEO가 시간 될 때 알아서 처리하길 기대하겠죠.
지금 처리 방식이 이와 유사합니다.
2.
어떤 네트워크 메시지가 왔을 때,
첫 2바이트/2바이트를 읽어서 size/protocolID를 추출하고
protocolID에 따라서 처리할 패킷 내용을 파싱을 해서 class로 만들어준 다음,
그것을 Handler로 전달해주고 있습니다.
HandlePacket을 자동화하지 않는다면
protocolID에 따라서 내용을 파싱하는 부분을 switch-case로 일일히 수동으로 만들어줘야 하는데
이런 노가다를 피하기 위해 만든 것입니다. (그런데 실제로 switch-case 200개로 처리하는 곳도 있긴 합니다)
서버 쪽에서는 [protocolID 읽기] -> [파싱 패킷 만들기] -> [handler로 넘기기]를 한 번에 하는 반면,
유니티 쪽은 [protocolID 읽기] -> [파싱 패킷 만들기] 까지만 한 다음 Queue에다 넣고,
게임 쓰레드에서 Queue 내용을 뽑아와서 다시 [handler로 넘기기]를 나눠서 하는 차이는 있지만
결과적으로 자동화된 부분을 사용하지 않는 것은 아닙니다.
참고로 이 부분은 Part7에서 다시 다루게 됩니다.
(자체 제작 프로토콜 -> protobuf로 이식하는 과정에서 다시 설명합니다)
3.
C++과 다르게 C#에서는 자체적으로 관리하는 쓰레드 풀이 있는데
그걸 사용하고 있기 때문에 별도로 만들어줄 필욘 없습니다.
(물론 쓰레드를 몇개 사용할 것인지 세부적으로 설정은 할 수 있긴 합니다)
4.
TLS는 필요에 따라 사용하는거지 꼭 이용해야 한다는 의미는 아니고,
대부분 너무 쓰레드 경합이 심한 부분에서 유용한 경우가 있지만
이것도 케바케로 다르기 때문에 뭔가를 공식화 하긴 애매합니다.
그리고 Part4에선 SendBuffer가 TLS을 이용하는 방식으로 구현이 되었는데,
스포일러를 드리자면 지금 만들고 있는 Part7에서
ProtoBuf로 SendBuffer를 대체할 예정이라 그나마 사용하던 TLS도 사라질 예정입니다.