Open()을 통해 큰 사이즈를 만들고 사용한 만큼 Close()에 넣어 할당하며, 큰 사이즈의 크기에서 점점 채워가며 사용하는 방식의 SendBuffer를 제작하였고 이제 본격적으로 패킷 작업을 위해 구성을 해놓을 것이다.
패킷의 값으로 구분하기
패킷을 전송하는 방식을 좋으나, 패킷만 봤을 때는 사이즈가 어느정도인지 모르기에 보통 첫 인자로 사이즈를 넣어주고, 두 번째로 ID를 넘겨주는 경우가 잦다. ID란 어떤 패킷인지의에 대한 구분 값이다. EX. 1은 이동 2는 스킬 등 (Int 나 short를 쓰는데 ushort로도 충분함(2바이트)
패킷을 보낼 때는 최대한 용량을 아껴주어야한다. 패킷을 보낼 때도 int로 size, id를 보내면 short 대비 4바이트를 더 사용하는 것이다. 이게 10,000명 이라면 40,000 바이트 이니 최대한 압축해서 사용하는게 중요함(int 는 4 short는 2 이므로 두 개 시 4바이트)
기존 Session Class에서 사용하던 OnRecv를 사용할 것 이다. Send 할 당시에도 size, id 설정 등의 변화가 있지만 우선 패킷 작업은 받을 때(OnRecv) 해당 패킷의 이상유무 검사를 통해 넘겨주며 작업 처리를 할 예정이다.
Packet의 검사를 통해 넘겨줄 처리를 해주기 위한 Class와 sealed 함수를 제작한다.
sealed 키워드
해당 Class를 상속 받은 곳에서, sealed 된 함수를 호출할 수 없게 막아주는 역할을 한다. 참고로 상속 받을 때 부모 클래스에 abstract 키워드가 붙은 함수는 꼭 구현을 해주어야 한다.
// Header의 기본 사이즈 설정을 위함
public static readonly int HeaderSize = 2;
public abstract class PacketSession : Session
{
// 뱉어 줄 값
int processLegnth = 0;
public sealed override int OnRecv(ArraySegment<byte> buffer)
}
이 함수 내에서는 내가 원하는 패킷이 모두 도착했는 지 확인 과정을 거칠 것이다.
while 루프를 돌며 오류가 있을 경우 break 해주고,
while (true)
{
// 최소한 헤더는 파싱할 수 있는지 확인
if (buffer.Count < HeaderSize)
break;
// 패킷이 완전체로 도착했는지 체크
// ushort만큼 긁어줄 예정
ushort datasize =
BitConverter.ToUInt16(buffer.Array, buffer.Offset);
// 패킷이 다 안왔으면 대기
if (buffer.Count < datasize)
break;
넘어온 buffer가 최소 사이즈 보다는 큰지 검사를 하고, 첫 번째 인자(size) 값이 버퍼의 크기보다 작으면 말도 안되기에 검사를 한 번 더 거친다.
위 조건들을 통과하면, buffer를 받아온 datasize 만큼 넘겨 주어 첫 번째 패킷들을(현재 size, id만 담긴 값) 넘겨준다.
// 위 조건들을 통과했으면 이제 패킷 조립가능
OnRecvPacket(new ArraySegment<byte>
(buffer.Array, buffer.Offset, datasize));
// buffer.Slice()를 통해 넘겨주는 것도 가능하다.
ArraySegment는 Heap 영역에 할당 되지 않기에 new 키워드를 사용해도 문제가 발생하지 않는다.
기존 Server에서 Session을 상속 받던 부분을 PacketSession으로 변경 해준다.
그 뒤, abstract로 생성한 OnRecvPacket에서 BitCoverter를 통해 받아온 인자 값이 잘 들어오는지 출력을 해볼 예정이다.
다시 OnRecv 함수 처리로 돌아와서 processLegnth에 datasize를 받은 방금 증가시키고, buffer에서는 사용한 부분을 제외하고, 다음 패킷들로 넘겨준다.
processLegnth += datasize;
// 위에 작업들을 모두 통과했다면 첫 번 째 패킷은 끝난거기에 다음 패킷으로 넘겨버림
buffer = new ArraySegment<byte>
(buffer.Array, buffer.Offset + datasize, buffer.Count - datasize);
간단하게 Send 처리 하던 부분에 size, packId가 담긴 Class 선언 후, 값을 대입하여 전송 해준다.
위와 같은 구조로 동작하며 패킷을 보내고 출력하는 작업 까지 마무리 했다. 패킷을 보내고 받는 과정을 알게되는게 재미있지만 과정이 좀 복잡해서 이해하고, 암기가 필요한 듯 하다.