C#/네트워크 관련

Serialization #2

tmd1 2024. 11. 26. 23:27
using ServerCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Server
{
    public abstract class Packet
    {
        public ushort size;
        public ushort packetId;

        public abstract ArraySegment<byte> Write();
        public abstract void Read(ArraySegment<byte> s);
    }

    class PlayerInfoReq : Packet
    {
        public long playerId;

        public PlayerInfoReq()
        {
            this.packetId = (ushort)PacketID.PlayerInfoReq;
        }

        public override void Read(ArraySegment<byte> s)
        {
            ushort count = 0;


            //ushort size = BitConverter.ToUInt16(s.Array, s.Offset);
            count += 2;
            //ushort id = BitConverter.ToUInt16(s.Array, s.Offset + count);
            count += 2;
            // TODO: 크기 넘어가면 exception 난다는데 이해하고 주석 수정
            // size, id 다음부터 읽는데 Write해서 보내준 크기 - 헤더정보를 제외했을 때
            // 읽어올 데이터의 크기만큼의 공간이 존재하지 않는다면 exception
            this.playerId = BitConverter.ToInt64(new ReadOnlySpan<byte>(s.Array, s.Offset + count, s.Count - count));
            count += 8;
        }

        public override ArraySegment<byte> Write()
        {
            ArraySegment<byte> s = SendBufferHelper.Open(4096);

            ushort count = 0;
            bool success = true;


            // s.Count 보다 넣어주는게 크면 false
            // TrtWriteBytes 이용해서 곧바로 ArraySement에 넣어줌
            count += 2; // size 크기 미리 넣음(unshort)
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), this.packetId);
            count += 2;
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), this.playerId);
            count += 8;

            // packet의 size 즉 count는 나중에 확정되므로 마지막에 보내줌
            // count의 저장되어 있는 값은 패킷의 size(=12)고 size의 크기는 2(unshort)임
            // count의 타입 유의 - count 타입이 int면 4 byte이므로 값이 덮어씌워 질 수 있음
            // 물론 지금은 하드코딩이라서 그런거지만..
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), count);

            if (success == false)
                return null;

            return SendBufferHelper.Close(count);
        }
    }


    public enum PacketID
    {
        PlayerInfoReq = 1,
        PlayerInfoOk = 2
    }

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

            Thread.Sleep(5000);
            Disconnect();

        }

        public override void OnRecvPacket(ArraySegment<byte> buffer)
        {
            ushort count = 0;

            
            ushort size = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
            count += 2;
            ushort id = BitConverter.ToUInt16(buffer.Array, buffer.Offset + count);
            count += 2;

            switch ((PacketID)id)
            {
                case PacketID.PlayerInfoReq:
                    {
                        PlayerInfoReq q = new PlayerInfoReq();
                        q.Read(buffer);

                        Console.WriteLine($"PlayerInfoReq : {q.playerId}");

                        break;
                    }
                    
            }

            Console.WriteLine($"ReceivePacketId : {id}, Size : {size}");
        }

        public override void OnDisconnect(EndPoint endPoint)
        {
            Console.WriteLine($"OnDisconnected : {endPoint}");
        }


        public override void OnSend(int numOfBytes)
        {
            Console.WriteLine($"Transferred bytes: {numOfBytes}");
        }
    }
}

 

 

using ServerCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace DummyClient
{
    public abstract class Packet
    {
        public ushort size;
        public ushort packetId;

        public abstract ArraySegment<byte> Write();
        public abstract void Read(ArraySegment<byte> s);
    }

    class PlayerInfoReq : Packet
    {
        public long playerId;

        public PlayerInfoReq()
        {
            this.packetId = (ushort)PacketID.PlayerInfoReq;
        }

        public override void Read(ArraySegment<byte> s)
        {
            ushort count = 0;


            //ushort size = BitConverter.ToUInt16(s.Array, s.Offset);
            count += 2;
            //ushort id = BitConverter.ToUInt16(s.Array, s.Offset + count);
            count += 2;

            // TODO: 크기 넘어가면 exception 난다는데 이해하고 주석 수정
            // size, id 다음부터 읽는데 Write해서 보내준 크기 - 헤더정보를 제외했을 때
            // 읽어올 데이터의 크기만큼의 공간이 존재하지 않는다면 exception
            this.playerId = BitConverter.ToInt64(new ReadOnlySpan<byte>(s.Array, s.Offset + count, s.Count - count));
            count += 8;

        }

        public override ArraySegment<byte> Write()
        {
            ArraySegment<byte> s = SendBufferHelper.Open(4096);

            ushort count = 0;
            bool success = true;


            // s.Count 보다 넣어주는게 크면 false
            // TrtWriteBytes 이용해서 곧바로 ArraySement에 넣어줌
            count += 2; // size 크기 미리 넣음(unshort)
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), this.packetId);
            count += 2;
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), this.playerId);
            count += 8;

            // packet의 size 즉 count는 나중에 확정되므로 마지막에 보내줌
            // count의 저장되어 있는 값은 패킷의 size(=12)고 size의 크기는 2(unshort)임
            // count의 타입 유의 - count 타입이 int면 4 byte이므로 값이 덮어씌워 질 수 있음
            // 물론 지금은 하드코딩이라서 그런거지만..
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), count);

            if (success == false)
                return null;

            return SendBufferHelper.Close(count);
        }
    }


    public enum PacketID
    {
        PlayerInfoReq = 1,
        PlayerInfoOk = 2
    }

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

            // 패킷을 최종적으로 보내기 전 까지는 사이즈를 알 수 없음
            PlayerInfoReq packet = new PlayerInfoReq() { playerId = 1001 };

            
            {

                ArraySegment<byte> sendBuff = packet.Write();

                if(sendBuff != null)
                    Send(sendBuff);
            }


        }

        public override void OnDisconnect(EndPoint endPoint)
        {
            Console.WriteLine($"OnDisconnected : {endPoint}");
        }

        public override int OnRecv(ArraySegment<byte> buffer)
        {
            string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
            Console.WriteLine($"[From Server] {recvData}");

            return buffer.Count;
        }

        public override void OnSend(int numOfBytes)
        {
            Console.WriteLine($"Transferred bytes: {numOfBytes}");
        }
    }
}