관리 메뉴

有希

Packet Serialization 본문

프로그래밍/C# 게임서버

Packet Serialization

有希. 2021. 9. 17. 20:46

간단하게는 볼록한 데이터형(?)을 평평하게 찌그러뜨려서 byte[]안에 담을 수 있도록 하는 것.

원시타입의 경우에는 byte크기가 정해져 있어서 그 사이즈를 예상할 수 있고, 가장 앞쪽에 packet size는 몇 이라고 기입할 수 있다.

하지만 string이나 구조체, 클래스와 같은 경우에는 임의로 사이즈를 줄였다 늘렸다 할 수 있기 때문에 사이즈를 정확히 몇이라고 정의할 수 없다. +멤버 변수를 다 정해놓았더라도 그 중에 string같은게 섞여있으면 또 사이즈가 바뀐다.

byte[]에 밀어넣어야 어떻게든 네트워크 상으로 전송할 수 있기 때문에, string이나 클래스처럼 사이즈가 가변적인 녀석을 평평하게 찌그러트려서 버퍼안에 밀어넣는 작업을 직렬화(Serialization)이라고 한다.

반대로, 이를 꺼내서 다시 볼록하게 만드는 작업을 역직렬화라고 한다.

BitConverter를 이용하는 방법도 있고, unsafe를 활용하여 직접적으로 포인터를 다루는 방법도 있는데 전자가 편한대신 조금 느리다.


보내는 것이야 그냥 직렬화해서 보내면 되지만, 받는 쪽에서는 항상 클라가 해킹의 위험이 있기 때문에 거짓말을 하고 있다고 가정하고 받아야 한다. 그래서 단순히 BitConverter에 ReadOnlySpan으로 size만큼만 잘라서 받는다.

만약 GetBytes같은 거로 읽어왔다가는 사이즈 만큼이 아닌 뒤의 버퍼값들도 죄다 읽어오기 때문에 악의적으로 size를 줄여서 보낸 뒤에 뒤쪽에는 함수 호출 스택을 바꿔서 다른 짓을 하게 될 위험도 있다.(이쪽 내용은 컴퓨터 보안 수업때 들은 내용을 토대로 시나리오를 덧붙인 내용입니다. 틀릴수도 있음)


string이나 클래스 같은 경우는 어떻게 직렬화를 할까?

C#에서는 기본적으로 UTF-16을 사용한다. "ABCD"같은 것을 Length와 같은 내장함수를 이용하면 byte[]로는 8인데, length값은 4가 나온다. 매 번 이걸 확인해서 *2 해줄 수도 없는 노릇이다. Encoding.Unicode.GetByteCount를 이용하여 byte수를 가져오면 잘 나온다.

이를 이용해서 마찬가지로 TryWriteBytes로 바이트에 밀어넣어준다. !주의할 점은 ushort 사이즈만큼 띄운 다음 넣는다는 점이다. 이렇게 하면 앞의 띄운 공간에는 실제로 쓰여진 Byte값을 써주면 된다.

클래스도 마찬가지로 내부 멤버 변수들을 써준 다음에 그 동안 센 byte수를 앞쪽의 ushort만큼 빈 공간에 써주면 된다.

 

'프로그래밍 > C# 게임서버' 카테고리의 다른 글

Job Queue  (0) 2021.09.17
Packet Generator  (0) 2021.09.17
RecvBuffer  (0) 2021.09.17
Connector  (0) 2021.09.17
Session#4  (0) 2021.09.09