나중에 직렬화 관련 코드는 매우 많이 사용되기 때문에 자동화를 해주는 것이 좋다.
이번 글은 자동화를 만들기 위해 어떤식으로 구현할지 미리 인터페이스를 짜본다.
💻 코드
패킷 추가
테스트할 임시 패킷을 추가한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Packet
{
    public ushort size;
    public ushort packetId;
}
// 유저 확인용으로 보내줄 패킷
class PlayerInfoReq : Packet
{
    public long playerId;
}
// 유저 확인될 시 보내줄 패킷
class PlayerInfoOk : Packet
{
    public int hp;
    public int attack;
}
// 패킷 ID
public enum PacketID
{
    PlayerInfoReq = 1,
    PlayerInfoOk = 2,
}
Server는 ClientSession Class를 만들어주고, Client는 ServerSession을 만들어준다.
각 Session은 서로의 도우미 역할로 어떤식으로 보내고 받는지 도와줄 것이다.
Client
BitConverter.TryWriteBytes를 통해 버퍼안에 데이터를 가져올 수 있다.
count로 다음 위치 확인 및 사이즈를 체크해준다.
만약 버퍼안에 데이터가 없는 경우 success가 false를 뱉으므로 Send할 수 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
namespace DummyClient
{
    class ServerSession : Session
    {
        public override void OnConnected(EndPoint endPoint)
        {
            Console.WriteLine($"OnConnected : {endPoint}");
            PlayerInfoReq packet = new PlayerInfoReq(){
                size = 4, packetId = (ushort)PacketID.PlayerInfoReq, playerId = 1001
            };
            // 4096 버퍼 사용하기 (이름이 길어 segment -> s)
            ArraySegment<byte> s = SendBufferHelper.Open(4096);
            bool success = true;
            ushort count = 0;
            // [직렬화 시작]
            // size 공간 +
            count += 2;
            // packetId 공간 +
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.packetId);
            count += 2;
            // playerId 공간 +
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.playerId);
            count += 8;
            // 총 사이즈는 다 넣어야 알 수 있기 때문에 마지막에 넣기 
            success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), count);
            // 얼마나 썼는지 알려주기
            ArraySegment<byte> sendBuff = SendBufferHelper.Close(count);
            // 조립에 성공하면 전송
            if (success)
                Send(sendBuff);
        }
    }
}
Server
size와 packetId는 정해져 있으니 먼저 구현하고,
그 다음 버퍼에는 전달 받을 데이터가 들어있으니 switch를 사용해 확인한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace Server
{
    class ClientSession : PacketSession
    {
        public override void OnRecvPacket(ArraySegment<byte> buffer)
        {
            // [역직렬화 시작]
            int 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:
                    {
                        long playerId = BitConverter.ToInt64(buffer.Array, buffer.Offset + count);
                        count += 8;
                        Console.WriteLine($"PlayerInfoReq : {playerId}");
                    }
                    break;
            }
        }
    }
}
BitConverter.TryWriteBytes가 선언이 안된다면
구글링을 좀 하다가 프레임워크를 추가 적용하는 방법을 몰라서 프로젝트를 새로 만들고
프로젝트 우클릭 -> 속성 -> 대상 프레임워크 확인대상 프레임워크가.Net Core가 아닐 경우 바꿔주도록 한다.- 만약 
.Net Core가 없다면 프로젝트를 다시 만들어서 프레임워크가 없는 콘솔창을 선택해 만들어준다. - 원래 사용하던 코드를 옮겨준다.