개인공부) 서버실습(29) - PacketSession

Justin·2022년 6월 21일
0

서버공부

목록 보기
28/45

✅ 지난시간

Open()을 통해 큰 사이즈를 만들고 사용한 만큼 Close()에 넣어 할당하며, 큰 사이즈의 크기에서 점점 채워가며 사용하는 방식의 SendBuffer를 제작하였고 이제 본격적으로 패킷 작업을 위해 구성을 해놓을 것이다.

📻 패킷 전송하기

패킷의 값으로 구분하기
패킷을 전송하는 방식을 좋으나, 패킷만 봤을 때는 사이즈가 어느정도인지 모르기에 보통 첫 인자로 사이즈를 넣어주고, 두 번째로 ID를 넘겨주는 경우가 잦다. ID란 어떤 패킷인지의에 대한 구분 값이다. EX. 1은 이동 2는 스킬 등 (Int 나 short를 쓰는데 ushort로도 충분함(2바이트)
short와 ushort

❓ 그냥 int 쓰면 안될까?

패킷을 보낼 때는 최대한 용량을 아껴주어야한다. 패킷을 보낼 때도 int로 size, id를 보내면 short 대비 4바이트를 더 사용하는 것이다. 이게 10,000명 이라면 40,000 바이트 이니 최대한 압축해서 사용하는게 중요함(int 는 4 short는 2 이므로 두 개 시 4바이트)


🆗 작업 순서

기존 Session Class에서 사용하던 OnRecv를 사용할 것 이다. Send 할 당시에도 size, id 설정 등의 변화가 있지만 우선 패킷 작업은 받을 때(OnRecv) 해당 패킷의 이상유무 검사를 통해 넘겨주며 작업 처리를 할 예정이다.

🔨 패킷 전송 Class 생성

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) 값이 버퍼의 크기보다 작으면 말도 안되기에 검사를 한 번 더 거친다.

💿 OnRecvPacket에 넘겨 작업하기

위 조건들을 통과하면, 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);

😁 Dummy Client Send 처리

간단하게 Send 처리 하던 부분에 size, packId가 담긴 Class 선언 후, 값을 대입하여 전송 해준다.

📈 진행 순서

  • 클라이언트 연결 요청
  • 서버 승인
    -> session.Start()를 통해 Recv 함수 동작
    -> OnConnected() 진입 및 패킷 전송(size, packeId)
  • Recv-> Register -> Complete -> 서버에서 OnRecv가 동작하며 size, packeId 출력

위와 같은 구조로 동작하며 패킷을 보내고 출력하는 작업 까지 마무리 했다. 패킷을 보내고 받는 과정을 알게되는게 재미있지만 과정이 좀 복잡해서 이해하고, 암기가 필요한 듯 하다.

profile
인디 게임을 만들며 공부하고 있습니다.

0개의 댓글