PacketSession

CJB_ny·2022년 2월 23일
0

Unity_Server

목록 보기
33/55
post-thumbnail

이때까지

RecvBuffer, SendBuffer 만들어서 주고 받는 인터페이스는 어느정도 윤곽이 나왔다.

오늘은 이어서 "패킷 작업"을 위해서 뭐가 필요한지 생각을 해볼 것인데

ServerCore의 Session에 기능을 추가를 할 것이다.

Session > OnRecv

를 보면 지금 받는게 ArraySegment인데 패킷으로 되면 어떻게 바뀌어야 할까?

우리는 지금 TCP를 패킷이 100바이트를 보냈다고 다오는게 아니라고 말했었다.

그래서 클래스 단위로 패킷을 보낸다고 햇을 때

이녀석이 짤려서 왔는지 아닌지 구별할 수 있는 뭔가가 있어야 한다.

그래서

class Packet
{
int hp,
int Id
}

이런식으로 있어서 Id에 따라서 패킷을 구별할 수 있을 것이다

Id가 1이면 이동패킷 이런식으로 패킷을 구분하는 방법이 잇을 것이다.

그런데 이것의 문제점은

Packet의 크기가 유동적으로 켜졌다 작아졌다 할 수 있다.

즉, 패킷 아이디만 보고 다른 패킷클래스의 Size는 맞추기 힘드니까

결국에는

public class Packet
{
int Size;
int ID;
}

이렇게 첫인자로 Size를 넣어주면 좋을거 같다라는 생각이 든다.

그래서 대부분의 패킷을 설계를 할때 첫인자로 Size를 넣어주고 두번째에 Id를 넘겨주는 경우가 많다.

이런식으로..

그래서 지금 size, Id를 int || short로 할것이냐? 인데

대부분 ushort로 해도 충분하다.

ushort == 2byte인데

이거만 사용해도 거의 뭐 충분하게 큰 불편함 없이 사용할 수 있다.

나중에 네트워크로 송수신할때 패킷을 최대한 압축을 해서 송수신 하는게 중요하다.

만약 int하면 4바이트라 100명의 유져한테 이동패킷 쏘면 만개가 나가면 4만 바이트인데

ushort로 만개쏘면 2만바이트라 2만바이트 절약했다.

즉 int, int 하는것보다 ushort, ushort하면 4만바이트 아낀다.


1. Packet 구분하는 Session만들기

이렇게 클래스 하나 만들어 주자.

이녀석도 abstract를 붙여줬기 때문에

Session에서

꼭 구현을 해야했던 이 아이들을 구현을 안해도 되었다.

PacketSession에서 이녀석을 override를 해줄 것이다.

그냥 ovrride가 아니라 sealed를 붙여서

다른 클래스가 PacketSession을 상속받더라도 OnRecv를 override하려고 하면은
이녀석은 못 사용하게 "동봉" 막는다는 뜻이다.

이렇게 한다.

그리고 OnRecv를 이제는

PacketSession을 상속받는 애들은 OnRecv대신 OnPacketRecv를 사용을 해라라고 abstract로 뚫어주자.

내부에서 OnRecv를 처리를 해서 OnPacketRecv를 보내 줄 것이다.


2. PacketSession구현

PacketSession의 OnRecv를 구현을 함 해보면

패킷을 보냈다는 것은

이런식으로 온다는 뜻인데

이렇게 2바이트씩 온다는 것이고 ( [ . . . ] 는 옵션으로 다른 내용이 온다는 것)

그리고 이게 경우에 따라

2바이트씩 온다는 것이고 ( [ . . . ] 는 옵션으로 다른 내용이 온다는 것)2바이트씩 온다는 것이고 ( [ . . . ] 는 옵션으로 다른 내용이 온다는 것)2바이트씩 온다는 것이고 ( [ . . . ] 는 옵션으로 다른 내용이 온다는 것)

이렇게 반복이 될 것이다.

OnRecv에서 Parsing을 하는데

여기 2byte가 먼저 왔는지 확인을 할 것이다.

(운 안좋게 1바이트 짤려서 오면 다음턴까지 ㄱㄷ)

그래서 패킷이 오면 이녀석을 까보아서

"내가 분석하고 있는 패킷이 몇바이트 짜리 패킷인지 봐가지고

해당하는 데이터가 다 올 때까지 기다렸다가.

그녀석을 처리 하는 방식으로 이루어 질 것이다.

precessLen을 놔두어서 몇바이트를 처리를 했는지 둘 것이다.

뻉뺑이를 돌면서 패킷을 처리를 할 수 있을때까지 돈다.

buffer.Count를 먼저 체크를 해야된다.

지금 buffer는 buffer.Array, Offset, Count로 넘어 올 것인데

이녀석이 최소한 2바이트 보다는 커야된다.

이렇게.

반대로 말하면 2보다 작으면

break;

(하드 코딩 하는게 좀 그러면)

이렇게 해주자.

두번째로는 패킷이 완전체로 왔는지 확인!

그렇다는 것은 이 2바이트 짜리를 까봐야 한다는 것이다.

이버젼을 사용을 하면으

이녀석이 뱉어 주는 것은

UInt 16 즉, 정확하게는 ushort만큼 긁어가지고 그녀석을 뱉어 줄 것인데

dataSize로 받아주고

buffer.Count가 dataSize보다 작다면 부분적으로 왔다는 것이니까

다시 break;

이렇게 두가지 예외를 다 통과를 했다고 하면은

여기서 이런식으로 뭔가를 해주면 될 것이다.


그다음에는

이렇게 preLen을 dataSize만큼 늘려주고

그다음에 중요한데

지금 while문을 돌고있었는데

여기 첫 2바이트를 추출 해가지고

ProLen += dataSize까지 왔다는 것은

이 부분까지 다 처리를 했다는 얘기가 되니까

지금 buffer가

이까지가 유효범위 인데

이부분까지 찝어서 옮겨줘야 한다는 얘기 이니까

buffer.Array에다가 시작 Offset은 buffer.Offset에다그 dataSize만큼 가야지

( 이부분 만큼 인것이다 )

반면 buffer의 크기는

이만큼인데 밑줄친 만큼 줄어드니까

buffer.Count - dataSize만큼 빼줘야 한다.

그러면 이제 buffer는 바뀐

이 녀석을 찝어주는 애가 된다.

그래서 이제

이것을 계속 반복하면 될 것이다.

이렇게 하다보면 내가 처리할 수 있는 대까지 패킷을 계속 처리를 하다가

더이상 못하겠다 싶으면 while안에서 break를 해가지고

처리한 byte수를

return ProcessLen으로 뱉어 주게 될 것이다.


그 다음 이제

여기다가 뭔가를 입력을 해줘야함.

1) 패킷을 만들어서 보내도되고

2) 해당 영역 찝어주는 것도 not bad

1) => 패킷이 해당하는 영역을 다시 찝어줘서 넘겨줄 것인데

이렇게 보내주는데 이것은

밑줄 친 부분까지 잘 파싱해서 사용해라! 라는 의미이다.


( OnRecv는 패킷을 보낼때 마다 호출이 되어서 계속 패킷이 쌓일 테니

while문에서 2바이트보다 크거나 같으면 OnPacketRecv에

이렇게 넣어주는게 맞는듯 )


그런데

이 앞에잇는 2바이트 짜리 사이즈가 실제로

실직적인 패킷내용의 사이즈를 넣어 줄 것인지

아니면

SizeHeader를 포함한 전체 사이즈를 넣어줄 것인지는 일단 정해야되는데

지금은, SizeHeader를 포함한 전체를 넣어주고 있다.


Slice 이용해서 buffer 잘라도되지만

ArraySegment는 struct == 구조체라 Heap영역에 할당이 안되고 stack영역에 할당이 되어서

부담없이 사용해도된다.


3. PacketSession 넘겨주고 난뒤

그래서 이렇게해서

PacketSession이라는 애를 받아서 사용을 하면은

여기

이렇게 파싱해서 ProcessLen하는 부분은 내부에서 알아서 해줄 것이고

실제로 유효범위만 찝어가지고 넘어가게 될텐데

이거를 컨텐츠 쪽에서

이녀석을 추출을 해가지고

이게 어떤 패킷인지

packetId에 따라서 switch 로 쭉 분기를 해서 처리를 하면 될 것이다.

4. 사용예제

Server > 로 가보면

Session이 아니라

PacketSession을 상속받도록 하자.

이거 사용하면 안됨 (이유는 설명했었다)

반대로 OnRecvPacket은 구현 무줙권.

요렇게.

그래서 이제

이부분 에다가 뭔가를 처리를 해줘야 한다.

여기 들어온것은 유효한 범위를

여기서 찝혀서 온 것이다.

그렇다는 것은 첫 2byte는 Size이고 그 다음 2byte는 packetId가 들어가 있을 것이다.


그 다음

로그만 찍어보기 위해서 ToUInt16 == 바이트 배열을 뽑아서 ushort로 뽑아 달라는 요청이다.

buffer는 시작 Offset 에다가

첫인자인 2바이틀 뽑으면 그게 size가 되는 것이다.

그다음에 이녀석을 한번 더 해주는데

이렇게 될 것이다.

그런데 offset은 buffer.Offset이 아니라 2를 더한만큼

이렇게 될 것이다.


지금은 이렇게 하드코딩을 하고있지만 나중에는 싹다 자동화로 진행한다.

그리고 이렇게만 하고 끝내도록 하겠다.


그래서 Server쪽은 GameSession으로 이루어져있는데

이녀석은 PacketSession을 상속받고있다.

근데 이녀석을 테스트 하기 위해서는 최소한 Dummy에서도 똑같은 방법으로 보내줘야 한다.

그래서

Dummy에서도 똑같이 옮겨 주도록 하자.

그리고 OnConnected에서 이런식으로 더미메세지를 보내고 있었는데

이부분을 좀 옮겨보도록 하겠다.

오른쪽 밑줄 친 부분을

이렇게 옮길 것이다.

그런데 여기서

            ArraySegment<byte> sendBuff = SendBufferHelper.Close(buffer.Length + buffer2.Length);

가 아니라 packet.size가 되어야 한다.

( packet.size는 진지하게 맞춰 주자면 ushort * 2라 4byte가된다 )

그래서 이까지는 별 문제 없어 보인다


그리고 Server쪽에서

이부분이 잘 들어 오고 잇는지 보는 것이니까

이부분 잠시 주석 처리하고 보도록 하자.

그래서 5초동안 받는데 종료되기 전에 OnPacketRecv가 다 되는 것을 보고 종료를 하자.

그러면 잘 받았고 5초뒤에 연결을 끊는다.


결국 이렇게해서 중요한 선수 작업을 끝냈다.

5. 정리

결국에는 나중에 패킷을 설계하기에 앞서서

항상 이렇게

2byte짜리로 사이즈를 확인을 한 다음에

그녀석을 조립해서

OnPacketRecv로 넘겨주는 것까지 작업을 해보았다.

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

0개의 댓글