본문 바로가기
cs공부/네트워크프로그래밍

네트워크 프로그래밍 - XML문서에서 패킷 패싱 및 패킷 데이터를 자동화 방식으로 읽고 쓸 수있는 형태의 템플릿 정의

by 코딩하는 돼징 2023. 8. 20.
반응형

XML문서에서 패킷 패싱하기

public static void ParsePacket(XmlReader r)

01 현재 Xml노드타입이 종료 요소인지 확인

 if (r.NodeType == XmlNodeType.EndElement)
    return;

02 현재 요소의 이름이 packet인지 확인

이름이 packet이 아닌 경우 무효한 패킷 노드로 간주하고 적절한 오류 메시지 출력

if (r.Name.ToLower() != "packet")
{
    Console.WriteLine("Invaild packet node");
    return;
}

03 name attribute값 확인

name어트리뷰트 값이 없거나 빈 문자열인 경우 오류메시지 출력

string packetName = r["name"];
if(string.IsNullOrEmpty(packetName))
{
    Console.WriteLine("Packet without name");
    return;
}

04 위의 조건들이 모두 충족 될 경우 PareMembers 출력

 ParseMembers(r);

패킷 내의 멤버들 파싱

01 현재 요소의 name attribute 가져오기

현재 파싱 중인 패킷의 이름이다.

string packetName = r["name"];

02 현재 파싱 중인 패킷의 하위 멤버들의 깊이 계산

int depth = r.Depth + 1;

03  객체를 읽어오면서 하위 멤버들을 하나씩 파싱

while(r.Read())

04 현재 읽은 노드의 깊이가 기대한 깊이와 다르다면 종료

현재 멤버들의 파싱이 끝났다고 간주

if (r.Depth != depth)
    break;

05 멤버의 이름이 없거나 빈 문자열인 경우 오류 메시지 출력

string memberName = r["name"];
if(string.IsNullOrEmpty(memberName))
{
    Console.WriteLine("Member without name");
    return;
}

06 현재 멤버 타입을 소문자로 변환하고 어떤 타입인지 처리한다.

string memberType = r.Name.ToLower();
switch(memberType)
{
    case "bool":
    case "byte":
    case "short":
    case "ushort":
    case "int":
    case "long":
    case "double":
    case "string":
    case "list":
        break;
    default:
        break;
}

패킷 데이터를 자동화 방식으로 읽고 쓸 수 있는 형태의 템플릿 만들기

이중 중괄호

문자열 내에 중괄호를 포함되어야 하므로 이중 중괄호를 사용해야 한다.

01 packetFormat

class PacketFormat
{
    // {0} 패킷 이름
    // {1} 멤버 변수들
    // {2} 멤버 변수 Read
    // {3} 멤버 변수 Write
    public static string packetFormat = @"
    class {0}
    {{
        {1}

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

        ReadOnlySpan<byte> s = new ReadOnlySpan<byte>(openSegment.Array, openSegment.Offset, openSegment.Count);

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

        {2}
        
        
    }}
    public ArraySegment<byte> Write()
    {{
        ArraySegment<byte> segement = SendBufferHandler.Open(4096);
        bool success = true;
        ushort count = 0;

        Span<byte> s = new Span<byte>(segement.Array, segement.Offset, segement.Count);

        count += sizeof(ushort);
   
        success &= BitConverter.TryWriteBytes(s.Slice(count,s.Length-count), {0});
        count += sizeof(ushort);
    
        {3}

        success &= BitConverter.TryWriteBytes(s, count);
        if (success == false)
        {{
            return null;
        }}

    return SendBufferHandler.Close(count);
    }}
}}
";

02 memberFormat

멤버 변수의 형식 정의

// {0} 멤버 변수 형식
// {1} 변수 이름
/*
    public int id;
    public short level;
    public float duration;
*/
public static string memberFormat =
    @"public {0} {1}";

03 readFormat

멤버 변수 read 코드의 형식 정의

// {0} 멤버 변수 형식
// {1} To 변수 형식
// {2} 변수 형식
public static string readFormat =
    @"this.{0} = BitConverter.{1}(s.Slice(count, s.Length - count));
    count += sizeof({2});";

04 readStringFormat

멤버 변수 read코드의 문자열 형식 정의

// {0} 변수 이름
public static string readStringFormat =
    @"ushort {0}Len = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
    count += sizeof(ushort);
    this.{0} = Encoding.Unicode.GetString(s.Slice(count, {0}Len));
    count += {0}Len;";

05 writeFormat

// {0} 변수 이름
// {1} 변수 형식
public static string writeFormat =
    @"success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), this.{0});
    count += sizeof({1});";

06 writeStringFormat

public static string writeStringFormat =
    @"ushort {0}Len = (ushort)Encoding.Unicode.GetByteCount(this.{0});
    success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), {0}Len);
    count += sizeof(ushort);
    count += {0}Len;";

 

 

 

 

 

 

 

 

참고 :  본 내용은 MMORPG  PART4 강의를 수강하여 작성하였습니다.

https://www.inflearn.com/course/%EC%9C%A0%EB%8B%88%ED%8B%B0-mmorpg-%EA%B0%9C%EB%B0%9C-part4

 

 

 

 

 

반응형

댓글