C# 53

유니티 연동 #4

이번 포스트에서는 이전에 만든 구조에 유니티를 추가하여 서버 프로그래밍을 해보겠습니다.우선, 이전에 존재하던 Player 오브젝트를 프리팹화하여 로직에서 생성하도록 하겠습니다. 새롭게 추가되는 스크립트는 다음과 같습니다. MyPlayer의 경우, 내가 조종하는 플레이어를 위한 스크립트입니다.컴포넌트로 해당 스크립트를 오브젝트에 붙여서 동작합니다. Player의 경우, 내가 조종하는 플레이어가 아닌 다른 플레이어를 위한 스크립트입니다.마찬가지로 컴포넌트로서 동작합니다. 마지막으로 PlayerManager의 경우, 패킷에 따라 로직을 수행하되 MyPlayer와 Player에 따라 다르게 로직을 수행합니다. 1) 유니티 프로젝트 - PacketHandlerclass PacketHandler{ public..

C# 2025.01.31

유니티 연동 #3

이번 포스트에서는 이전에 만든 구조를 조금 더 개량해 간단한 프로젝트를 만들어보겠습니다.우선, 패킷 구조를 변경하여 현실적인 패킷 구조를 만들어보겠습니다. 1) 패킷 구조 xml  총 6개의 패킷 구조로 변경되었습니다.각각 다음과 같이 동작합니다. S_BroadcastEnterGame 에서는GameRoom에 입장한 신규 플레이어를 기존의 플레이어들에게 브로드캐스트하고playerId를 기준으로 지정된 3차원 좌표계에 소환합니다. C_LeaveGame의 경우 플레이어가 GameRoom을 떠나는 경우에 사용합니다. S_BroadcastLeaveGame의 경우 플레이어가 GameRoom을 떠나는 경우 사용하고,pla..

C# 2025.01.30

유니티 연동 #2

이번 포스트에서는 이전의 코드에서 유니티의 자료형 중 하나인 GameObject를 사용해보겠습니다.그러나 이전의 상태에서 유니티의 자료형 즉, 유니티의 데이터를 사용하는 경우 실행되지 않는 문제가 발생하게 됩니다. 그 이유는 다음과 같은데,현재 네트워크 패킷은 유니티의 메인 스레드가 아닌 ThreadPool에 저장된 패킷을 가져와 사용하고 있습니다.이때 유니티에서는 게임의 스레드가 아닌 다른 스레드에서 게임 요소와 관련된 로직을 수행하는 것을 원천봉쇄하기에 실행이 되지 않습니다. 따라서 이를 위해 만들어진 패킷을 바로 사용하는 것이 아닌 큐에 일시적으로 보관하고 보관된 패킷을 유니티에서 사용할 수 있도록 조정하여 사용하도록 하겠습니다. 1) 유니티 프로젝트 - PacketQueuepublic class ..

C# 2025.01.28

유니티 연동 #1

이번 포스트에서는 이전에 만든 네트워크 프로그램을 Unity와 연결하여 수행하도록 하겠습니다.우선 이번 포스트에서는 클라이언트를 만들어보도록 하겠습니다. 유니티 에디터에서 클라이언트 프로젝트를 하나 생성하고 필요한 스크립트를 가져오겠습니다. 1) 서버 - 클라이언트 공용으로 사용하는 스크립트 공용으로 사용하는 스크립트 중에서, 이전의 Listener와 JobQueue 그리고 PriorityQueue의 경우서버 단계에서 사용하므로 가져오지 않습니다. 또한, 클라이언트는 ServerSession을 사용하므로 ServerSession을 위의 경로에 포함하였습니다. 2) 클라이언트에서만 사용하는 스크립트 클라이언트에서 패킷을 보내고 받기 위한 스크립트를 위와 같이 준비하였습니다. 3) GenPackets.bat..

C# 2025.01.28

JobTimer

현재 상태의 코드에서는 하나의 GameRoom 만이 존재하여 문제없이 동작하지만,만약 현재 GameRoom 외에도 다른 용도의 Room들이 추가되면 동시에 개별 Room들의 작업을 처리해야 하므로 부하가 발생하게 됩니다. 따라서 이번 포스트에서는 해당 문제를 해결하기 위한 작업을 수행해보겠습니다. 1) Server - 메인 스레드에서 Tick을 통한 처리class Server{ . . . static void Main(string[] args) { . . . int roomTick = 0; while (true) { int now = System.Environment.TickCount; ..

C# 2025.01.27

패킷을 모아서 전송하기

이번 포스트에서는 이전의 포스트에서 미리 예고하였던패킷을 모아서 전송하는 방법으로 기존의 코드를 수정해보겠습니다. 1) Serverclass Server{ static Listener serverListener = new Listener(); // 새로운 채팅방을 위한 GameRoom 생성 public static GameRoom Room = new GameRoom(); static void Main(string[] args) { . . . while (true) { Room.Push(() => Room.Flush()); Thread.Sleep(250); } }} Server의..

C# 2025.01.27

JobQueue #2

이번에는 이전의 포스트에서 사용한 람다식을 이용하여 Action을 자동으로 수행하는 방식이 아닌새로운 Task 단위를 만들어 이를 수동으로 수행하는 방식으로 JobQueue를 구현해보겠습니다. 1) TaskQueueinterface ITask{ void Execute();}// Task 중에서 Broadcast를 수행하는 Taskclass BroadcastTask : ITask{ GameRoom _room; ClientSession _clientSession; string _chat; // 생성자에서 GameRoom, ClientSession, Chat을 초기화함 BroadcastTask(GameRoom room, ClientSession clientSession, str..

C# 2025.01.22

JobQueue #1

Command 패턴을 구현하면서 최대한 C# 문법을 사용하겠습니다.또한 Command 패턴을 사용하므로 이전처럼 직접적인 Action을 수행하지 않고 최대한 JobQueue에 기록하도록 기존의 코드를 수정할 필요가 있습니다. 1) JobQueuepublic interface IJobQueue{ void Push(Action job);}public class JobQueue : IJobQueue{ Queue _jobQueue = new Queue(); object _lock = new object(); bool _flush = false; public void Push(Action job) { bool flush = false; // 락을 걸어 비동..

C# 2025.01.22

Command 패턴

이전 포스트에서 스레드의 양이 늘어나면 막대한 부하가 발생하여결국 싱글 스레드를 사용하는 것보다 못한 작업효율이 나타난다 하였습니다.그 이유를 정리하면 다음과 같습니다. 1) 발생하고 있는 문제 이와 같은 문제가 발생하는 이유은 스레드가 작업을 받음과 동시에 이를 처리까지 수행하기에 발생합니다.이런 상황에 추가적으로 lock을 통해 다른 스레드의 자원 점유를 막아 하나의 스레드만을 이용하여 작업을 수행하므로 대기하는 스레드들이 쌓이게 되어 결국 대기가 길어지는 비효율적인 상황이 발생하게 됩니다. 2) 해결 방법 따라서 이를 해결하기 위해 다른 스레드들은 작업을 받게 되면 Job Queue에 작업을 기록하고, 기록된 작업을 전문적으로 처리하는 스레드를 만들어 해당 작업을 처리하게끔 수정하겠습니다. 3) C..

C# 2025.01.22

채팅 테스트 #2

이번 포스트에서는 지난 포스트에 이어 클라이언트 단계에서 채팅 프로그램을 만들겠습니다. 1) Connectorpublic class Connector{ . . . // 연결을 수행하는 함수 public void Connect(IPEndPoint endPoint, Func sessionFactory, int connectCount = 1) { for (int i = 0; i  우선, 기존의 Connector의 Connect 함수를 수정하여Connect를 connectCount만큼 수행하도록 변경하였습니다.  2) PacketFormat class PacketFormat { // {0} 패킷 등록 public static string m..

C# 2025.01.21