Serialization #2

CJB_ny·2022년 2월 24일
0

Unity_Server

목록 보기
35/55
post-thumbnail

패킷을 직렬화를 해서 보내고

받는쪽에서는 비직렬화를 해서 패킷을 꺼내는 것 까지 해보았다.

오늘은 나중에 자동화를 하기위한 준비작업 &&

조금 인터페이스적인 부분을 사용을 하기 쉽게 만들것인데

1. Write 수정

지금

패킷을 직렬화 하는 부부에서 하는게 너무 많다.

이런부분들을 함수화 해서 자동화를 해주는 작업을 해볼것이다.

Packet에는 위의 사진처럼 "쓰는 부분"과 쓴 부분을 빼내서 "읽는 부분"이 있을 것이다.

이것을 최상위 class인 class Packet에다가 구현을 해주도록 하자.

이렇게 바꿔주도록 하겠다.

PlayerInfoReq도 추상클래스 구현 ㄱㄱ

그리고 Write하는 부분은 이전에 만들 었던

이부분을 넣어주면 될 것이다.

이렇게 가지고 와서 살펴보면은

얘 자체가 패킷이니까

this로 자신의 변수를 참조를 하라고 하겠다.

그리고 생성자를 만들어서

packetId를 설정을 해주도록 하겠다.

그리고 원래는 success가 아니면 안보내줬는데

null이라고 뱉어 주도록 하겠다.

이렇게

그러면 뱉어주는게 ArrarySegement이기는 할텐데 null로 되있어서 구분 씹가능.


2. Read 수정

Read의 경우 클라세션에

이렇게 넣어놨었는데

여기서 먼저 파싱을해서 포로토콜 id를 뽑아낸다음에

아이디에 따라 구분을 해서 여기서 만들어 줘야 할 것이다.

그렇다는 것은

이부분은 필수적으로 들어가야한다.

일단, 이렇게 옮겨 주자.

이부분도 옮긴다.

그리고 설령

이부분이 Read안에 있다고 하더라도

PlayerInfoReq가 왔다는 것을 알기 위해서는

OnRecvPacket에서 한번 까보기는 해야할 것이다.(id가 뭔지 알기 위해서)

(그런데 size, id를 Read에서 하는게 맞나 싶기는 하다)

id는 여기서 뽑아서 사용을 안해도된다.

이미 이까지 들어왔다는 뜻이기 때문에

현재

이 ArraySegmet가 "나의 프로토콜"을 사용하고있다.

즉, 내 자신이다 == PlayerInfoReq이다! 라는 것을 알 수 있으니까

이녀석은 굳이 추출할 필요 없을 것이다.

그래서

이런식으로 추출이 될텐데

짖금은 playerId가 이런식으로 추출이 될텐데

this를 붙여주는데 이렇게하면

이 패킷 클래스 자체의 인스턴스를

여기있는 정보로 채워주는 그런 역할을 할것이고

별건 아니고 지난 시간에 했던것을 class안에다가 넣어준것 뿐이다.


그다음 GameSession에서

이렇게 packetId빼주고

이제 packet.Write를 하게되면 내부적으로

sendBuffer에서 buffer를 하나 뽑아와가지고 써주는 작업까지 한다음에

s로 return 값 받아와서 null이 아닐 경우에 보내면 될 것이다.


그래서 나중에는 인게임 코드 내에서도

패킷을 주고받을 일이 당연히 생길 텐데

그럴때는

이런식으로 패킷 클래스를 하나 파주어서

그녀석을

이런식으로

Write를 해서 직렬화를 한다음에 바이트 배열로 만들어서 Send로 보내주면 된다는 얘기이다.


그리고 Send를 해서 받는 입장에서도

복잡하게 찾아서 할 필요 없이

PlayerInfoReq라고 하면은

long PlayerId = BitConverer로 막 하는게 아니라

이렇게 해주면 될 것이다.

( 근데 빨간줄이 뜨는 이유는 Dummy의 ServerSession에다가만 PlayerInfoReq를 작업을 해서 패킷부분이 안 맞아서 에러가 뜨는 중이다)

그래서 여기서 객체를 만들어 주고

Read를 해주면 DeSerialize 작업을 해가지고

buffer에 있는 값(정보, 데이터)들을 뽑아서

PlayerInfoReq에다가 빼내 줄 것이다(넣어줄? 것이다)

이렇게 굿굿.

이까지해서 첫번째 수정 끝


테스트를 해보면

잘됨


그런데

class Packet에서

size, packetId는 직접적으로 사용할 일이 거의 없는데 여기다가

이렇게 넣어주는 부분이 맞는지 모르겠다.

그래서 굳이 this.packetId를 안하고

이렇게해도 별 상관은 없다.


그리고 Packet

의 Write하는 부분은 온전히 우리가 컨트롤 하고있어서 사실 별다른 문제는 없다.

그런데

Read의 경우

이부분은 문제가 될 수 있다.

애당초 Read를 하는 부분이 어딘지를 살펴보면은

뭐 이런 부분인데

지금은 클라 -> 서버로 패킷을 보내는데

지금 패킷을 까보면서 id로 switch문으로 구분해서 작업을 하고 있었다.

여기 size가 넘겨받은 buffer의 size와 같은지는 모른다!

서버를 만들때는 클라에서 항상 거짓말을 한다고 가정을 하고 만드는게 중요하다.

항상 클라에서 보낸 정보는 반정도만 믿고 의심을 해야한다.


우리가 Write를 하면

이렇게 총 12바이트를 보내고있었는데

보낼 버퍼의 사이즈를 4라고 거짓말을 하고


이렇게 보내면

다 정상적으로 오고 우리가 거짓말한 값인 사이즈만 4로 바뀌어서 오게된다.

결론은

패킷 Header에 있는 정보는 믿을 수 없고 참고만 해야된다! 라는 것이다.

그래서 패킷 조작을해서 보내더라도 코드를 수정해서 다 감지를해서 보내도록 해야된다는 것인데

우리가 작업한게 뭔지 살펴보면은

[][] [][] [][] [][] [][] [][]

이렇게 12바이트가 와야 정상인데

packetHeader에다가 size가 4라고 거짓말을 한것이다.

그러면 유효범위가 4바이트라고

이렇게 딱 집어서 Read를 호출해 줄 것이다.

근데 그렇다고해서 밑줄 친 부분말고 나머지 부분이

메모리 상으로 없는 부분이 아니다.

데이터가 없는것이 아니기때문에

사이즈는 4바이트라고 했었어도 실제로는 데이터가 들어가 있기는 때문에

사이즈를 체크를 안하고

이런식으로 강제로 Bitconverter로 강제로 추출을하면은

메모리에 값이 있기 떄문에 값을 가져오게되어서 그런 것이다.


그래서 이부분을 어떻게 고칠지 보면은

Read에서

이부분을 100%로 무조건 Biuconverter로 하는게 아니라

충분한 공간이 있는지를 계속 체크를 해야된다는 얘기 이다.

그래서 이버젼을 사용하면 조금더 안전할거같다라는 생각이 든다.


반대쪽도 똑같이 수정 ㄱㄱ


실행을 해보면

이렇게 에러가뜬다.

여기 보면 거짓말로 (ushort)4로 보냈는데

s안에는 Array Count == 4로 보내준 대로 들어가있다.

근데 지금 count가 4나 증가를 했기 때문에 밑줄 부분의 결과값은 0이 될 것이다.

s.Count - count = 0;

이상태에서 실행을 한번 더 해보면

Session > OnRecvCOmpleted의

Exception으로 이동하는 것을 볼 수 있다.

그래서 packetHeader에 있는 값들을 절반정도만 신용을 하고

서버 코드를 짜는 것이다

그러다가 에러가 나면 그때그때 고친다.


3. 정리

그래서 지난시간 까지 만들어 봣던

직렬화와 비직렬화를

패킷클래스를 만들어서 배치를 시키는 작업까지 해보았다.

그래서 다음시간에는 가변적인 길이를 갖는 패킷? 패킷정보들을 어떻게 처리를 할지 고민을 해보도록 하자.

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글