반응형
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
반응형
'cs공부 > 네트워크프로그래밍' 카테고리의 다른 글
네트워크프로그래밍 - HTTP와 HTTPS (0) | 2024.03.11 |
---|---|
네트워크프로그래밍 - XML형식으로 패킷 정의 +) XML, 마크업 설명 (0) | 2023.08.19 |
네트워크 프로그래밍 - List 자료형 packet에 넣는 법 (0) | 2023.08.17 |
네트워크프로그래밍 - ENCODING(ASCII,UTF-8,UTF-16) (0) | 2023.08.08 |
네트워크프로그래밍 - packetId와 size에 대한 이슈(client의 거짓말, ReadOnlySpan) (0) | 2023.08.07 |
댓글