(C# : Server) PacketSession

Posted by : at

Category : Charp-Server



지금까지 구현은 아래와 같이 되어있는데. 좀 더 현실적으로 바꿔보자

class Knight
{
    public int hp;
    public int attack;
}

class GameSession : Session
{
    public override void OnConnected(EndPoint endPoint)
    {
        Console.WriteLine($"[OnConnected] {endPoint}");

        Knight kinght = new Knight() { hp = 100, attack = 10 };

        // 보내는 부분
        ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
        byte[] buffer = BitConverter.GetBytes(kinght.hp);
        byte[] buffer2 = BitConverter.GetBytes(kinght.attack);
        Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
        Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
        ArraySegment<byte> sendBuffer = SendBufferHelper.Close(buffer.Length + buffer2.Length);

        Send(sendBuffer);
        Thread.Sleep(1000);
        Disconnect();
    }

    // ...
class Packet
{
    public int hp;
    public int attack;
}

class GameSession : Session
{
    public override void OnConnected(EndPoint endPoint)
    {
        Console.WriteLine($"[OnConnected] {endPoint}");

        Packet packet = new Packet() { hp = 100, attack = 10 };

        // 보내는 부분
        ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
        byte[] buffer = BitConverter.GetBytes(packet.hp);
        byte[] buffer2 = BitConverter.GetBytes(packet.attack);
        Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
        Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
        ArraySegment<byte> sendBuffer = SendBufferHelper.Close(buffer.Length + buffer2.Length);

        Send(sendBuffer);
        Thread.Sleep(1000);
        Disconnect();
    }

여기서 또 발생하는 문제가 TCP의 특성상 패킷이 한 번에 들어올수도 여러번에 나눠서 들어올 수 있다. -> 패킷의 ID를 정해서 다들어왔나 들어오지 않았나 판별하면 어떨까?
그런데 패킷 ID만 보고는 유동적으로 변하는 패킷의 사이즈(Ex) String)경우 알수 없으니 사이즈 정보 자체를 보내보자

class Packet
{
    public ushort size;
    public ushort packetId;
}

class LoginOkPacket : Packet
{
    // ...
}

패킷을 파싱하는 Session을 별도로 만들어보자

public abstract class PacketSession : Session
{
    public static readonly short HeaderSize = 2;

    public sealed override int OnRecv(ArraySegment<byte> buffer)
    {
        int processLen = 0;

        while(true)
        {
            // 헤더파싱
            if(buffer.Count < HeaderSize)
                break;

            ushort dataSize = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
            if (buffer.Count < dataSize)
                break;

            OnRecvPacket(new ArraySegment<byte>(buffer.Array, buffer.Offset, dataSize));

            processLen += dataSize;
            buffer = new ArraySegment<byte>(buffer.Array, buffer.Offset + dataSize, buffer.Count - dataSize);
        }

        return processLen;
    }

    public abstract void OnRecvPacket(ArraySegment<byte> buffer);
}

실제사용은

class Knight
{
    public int hp;
    public int attack;
}

class GameSession : PacketSession
{
    public override void OnRecvPacket(ArraySegment<byte> buffer)
    {
        ushort size = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
        ushort id = BitConverter.ToUInt16(buffer.Array, buffer.Offset + 2);
        Console.WriteLine($"RecvPacketID : {id}, Size {size}");
    }
class Packet
{
    public int size;
    public int packetId;
}

class GameSession : PacketSession
{
    public override void OnConnected(EndPoint endPoint)
    {
        Console.WriteLine($"[OnConnected] {endPoint}");

        Packet packet = new Packet() { size = 4, packetId = 7 };

        // 보내는 부분
        for(int i = 0; i < 5; i++)
        {
            ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
            byte[] buffer = BitConverter.GetBytes(packet.size);
            byte[] buffer2 = BitConverter.GetBytes(packet.packetId);
            Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
            Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
            ArraySegment<byte> sendBuffer = SendBufferHelper.Close(packet.size);

            Send(sendBuffer);
        }

        //Thread.Sleep(1000);
        //Disconnect();
    }

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links