packet serialization

ㅋㅋ·2022년 11월 1일

csharp게임서버

목록 보기
13/16

송신 측은 패킷을 만들어 보내기 위해 데이터들을 바이트 단위로 만들어 내고,

수신 측은 받은 바이트 데이터들을 예상하는 데이터들로 변환하는 과정


  • read (deserialization)
public override void Read(ArraySegment<byte> segment)
{
    ushort count = 0;
    ReadOnlySpan<byte> s = new ReadOnlySpan<byte>(segment.Array, segment.Offset, segment.Count);
    
    count += sizeof(ushort); // packet size count

    count += sizeof(ushort); // packet id count

    this.playerID = BitConverter.ToInt64(s.Slice(count, s.Length - count));
    count += sizeof(long); //long data count

    ushort nameLength = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
    count += sizeof(ushort); //ushort data count

    this.name = Encoding.Unicode.GetString(s.Slice(count, nameLength));
    count += nameLength; //string data count

    ushort skillCount = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
    count += sizeof(ushort);

    skills.Clear();
    for (int i = 0; i < skillCount; i++)
    {
        SkillInfo newSkill = new SkillInfo();
        newSkill.Read(s, ref count); //struct data count
        skills.Add(newSkill);
    }
}

패킷을 받은 후 저장된 버퍼를 가지고 데이터 순서 및 크기대로 파싱

string과 같은 가변적 데이터는 데이터의 byte 길이를 먼저 받아 해당 길이만큼을 파싱

list같은 컨테이너는 데이터의 수를 먼저 받고, 해당 데이터만큼을 반복하며 파싱


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

    Span<byte> s = new Span<byte>(segment.Array, segment.Offset, segment.Count);
    ushort count = 0;
    bool success = true;

    count += sizeof(ushort); //추후 패킷의 사이즈가 들어갈 공간을 비워둠

    success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), (ushort)PacketID.PlayerInfoReq);
    count += sizeof(ushort);

    success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), this.playerID);
    count += sizeof(long);

    // player name
    ushort nameLength = (ushort)Encoding.Unicode.GetBytes(this.name, 0, this.name.Length, segment.Array, segment.Offset + count + sizeof(ushort));
    // string 바이트의 길이가 들어갈 2바이트를 건너 뛰고 string 데이터를 먼저 바이트에 써넣고, 

    success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), nameLength);
    // 그 후 계산된 string의 바이트 길이를 앞에 바이트로 써넣는다.

    count += sizeof(ushort);
    count += nameLength;

    // skill info list size
    success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), (ushort)skills.Count);
    count += sizeof(ushort);
    
    // skill info list
    for (int i = 0; i < skills.Count; i++)
    {
        success &= skills[i].Write(s, ref count);
    }

    success &= BitConverter.TryWriteBytes(s, count);

    if (success == false)
    {
        return null;
    }

    return SendBufferHelper.Close(count);
}

위 방법은 가장 쉬운 방법으로 구현되었고, 이를 최적화 하기 위해서

프로토 버프나 플랫버퍼 라이브러리를 사용할 수 있음

0개의 댓글