지금 우리가 작업한 코드가지고 뭔가를 시작하기엔 되게 막막하다. 사실상 컨텐츠단에서 사용할 준비를 전부 맞췄고 서버와 클라가 잘 통신하기에 사실 문제는 없지만 어떻게 구조를 짜야하는지 감이 안오니 테스트를 해보고 유니티에 연동해보자.
채팅
우리가 먼저 해볼거는 채팅이다. 채팅은 mmorpg건 아니건 다른 게임, 웹, 앱 등에서도 많이 등장한다. 그리고 어떤 서버든 채팅서버로 테스트를 많이 진행한다. 채팅을 구현할 수 있으면 다른것도 구현이 가능하기 때문이다. 이번 포스팅은 이 채팅을 간단히 구현해보고 문제점에대해 알아보자.
먼저 간단히 해보기 위해 패킷은 클라이언트 채팅 서버 채팅 두개로만 진행하기에 PDL 파일을 이렇게 수정한다.
그리고 PacketForamt을 통해 GenPackets 파일을 만들어준다.(bat 파일을 이용하면 편하다.)
먼저 시작해야할 것은 ClientSession에서 클라이언트가 접속했을때, 지금은 아무런 동작도 하지 않지만 클라이언트를 채팅서버에 입장시켜주는 것을 한번 해보자. 그러기 위해서는 방이라는 개념을 만들기 위해서 GameRoom.cs 파일을 만들어준다.
using System;
using System.Collections.Generic;
using System.Text;
using Server.Session;
namespace Server
{
class GameRoom
{
List<ClientSession> _sessions = new List<ClientSession>();
object _lock = new object();
public void Enter(ClientSession session)
{
lock (_lock)
{
_sessions.Add(session);
session.Room = this;
}
}
public void Leave(ClientSession session)
{
lock (_lock)
{
_sessions.Remove(session);
}
}
}
}
using System;
using System.Threading;
using ServerCore;
using System.Net;
namespace Server.Session
{
class ClientSession : PacketSession
{
public int SessionId { get; set; }
public GameRoom Room { get; set; }
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected : {endPoint}");
Program.Room.Enter(this);
Thread.Sleep(5000);
Disconnect();
}
public override void OnRecvPacket(ArraySegment<byte> buffer)
{
PacketManager.Instance.OnRecvPacket(this, buffer);
}
public override void OnDisconnected(EndPoint endPoint)
{
SessionManager.Instance.Remove(this);
if(Room != null)
{
Room.Leave(this);
Room = null;
}
Console.WriteLine($"OnDisconnected : {endPoint}");
}
public override void OnSend(int numOfBytes)
{
Console.WriteLine($"Transferred bytes: {numOfBytes}");
}
}
}
이렇게 해서 클라이언트가 접속했을 때 방으로 접속 시켜준다.
이제 컨텐츠단에서 즉, Handler에서 구현을 해주면 된다.
using Server.Session;
using ServerCore;
class PacketHandler
{
public static void C_ChatHandler(PacketSession session, IPacket packet)
{
C_Chat chatPacket = packet as C_Chat;
ClientSession clientSession = session as ClientSession;
if (clientSession.Room == null)
return;
clientSession.Room.Broadcast(clientSession, chatPacket.chat);
}
}
그렇다면 Broadcast를 구현하기 위해 다시 Room에 추가해준다.
public void Broadcast(ClientSession session, string chat)
{
S_Chat packet = new S_Chat();
packet.playerId = session.SessionId;
packet.chat = chat;
ArraySegment<byte> segment = packet.Write();
lock (_lock)
{
foreach(ClientSession s in _sessions)
{
s.Send(segment);
}
}
}
이로써 어떤 클라이언트가 접속하면 서버는 채팅 서버에 입장시켜주고 클라에서 메시지를 보냈다고 가정하면 클라가 채팅 서버에 있는지 확인하고 있다면 Room안에 있는 clientSession 전부에게 send를 하게된다. 여기서 멀티쓰레드 환경임을 주의하자
이렇게 실행하게되면 만약 클라이언트가 100명이라고 하면 100명이 패킷을 보내고 바로 Broadcast를 진행해서 100명에게 돌려준다 즉, 100*100 번의 패킷 전송이 이루어져야하기때문에 딜레이가 발생한다.
멀티쓰레드의 단점인 것이다. 이를 해결하기 위해 JobQueue에 대해 알아보자.
'Unity > 온라인 RPG' 카테고리의 다른 글
[게임 서버] Unity와 서버 연동 (1) | 2024.02.06 |
---|---|
[게임 서버] JobQueue - 서버 과부화를 줄이기 위한 패킷 처리 방법 (0) | 2024.02.05 |
[게임 서버] 패킷 직렬화 - Packet Generator (0) | 2024.01.30 |
[게임 서버] 패킷 직렬화 - Serialization (1) | 2024.01.24 |
[게임 서버] 네트워크 프로그래밍 - Connector, TCP? UDP?, Buffer와PacketSession (1) | 2024.01.22 |