C#/네트워크

[c#][서버] Serialization (2)

goliot 2024. 6. 9. 16:51
반응형

string이나 list같은 가변크기의 패킷을 어떻게 처리하나?

1. string 처리

  • 앞에 2바이트를 이 문자열의 크기로 정하고
    • 뒤에를 내용으로 채우면 된다.
//string -> len[2b], byte[내용] 로 보내면 되지 않을까
Span<byte> s = new Span<byte>(segment.Array, segment.Offset, segment.Count);

ushort nameLen = (ushort)Encoding.Unicode.GetBytes(this.name, 0, name.Length, segment.Array, segment.Offset + count + sizeof(ushort));
success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), nameLen);
count += sizeof(ushort); //nameLen의 공간
count += nameLen; //name
//Write 부분

//string
ReadOnlySpan<byte> s = new ReadOnlySpan<byte>(segment.Array, segment.Offset, segment.Count);
ushort nameLen = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
count += sizeof(ushort);
this.name = Encoding.Unicode.GetString(s.Slice(count, nameLen));
//Read 부분
  • Write쪽은 일반 Span, Read쪽은 ReadOnlySpan을 활용하여 안정성을 높임
  • Encoding.Unicode -> UTF-16 이라는 의미
  • GetBytes = string -> Byte배열로 만들어 주는 것, 반환값은 사이즈
  • GetString = Byte배열 -> string 변환

2. List 처리

public struct SkillInfo
{
    public int id;
    public short level;
    public float duration;
}

public List<SkillInfo> skills = new List<SkillInfo>();
  • 이런 형식의 리스트는 어떻게 처리할까?
public struct SkillInfo
{
    public int id;
    public short level;
    public float duration;

    public bool Write(Span<byte> s, ref ushort count)
    {
        bool success = true;
        success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), id);
        count += sizeof(int);
        success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), level);
        count += sizeof(short);
        success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), duration);
        count += sizeof(float);
        return success;
    }

    public void Read(ReadOnlySpan<byte> s, ref ushort count)
    {
        id = BitConverter.ToInt32(s.Slice(count, s.Length - count));
        count += sizeof(int);
        level = BitConverter.ToInt16(s.Slice(count, s.Length - count));
        count += sizeof(short);
        duration = BitConverter.ToSingle(s.Slice(count, s.Length - count));
        count += sizeof(float);
    }
}

public List<SkillInfo> skills = new List<SkillInfo>();
  • 해당 구조체 안에 함수를 직접 구현하여 사용하게 구현한다
//skill list
skills.Clear();
ushort skillLen = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
count += sizeof(ushort);
for(int i=0; i<skillLen; i++)
{
    SkillInfo skill = new SkillInfo();
    skill.Read(s, ref count);
    skills.Add(skill);
} //Read측

//skill list
success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), (ushort)skills.Count);
count += sizeof(ushort);
foreach(SkillInfo skill in skills)
{
    success &= skill.Write(s, ref count);
}//Write 측
반응형