public abstract class PacketSession : Session
{
public static readonly int HeaderSize = 2;
// [size(2)][packetId(2)][ ... ][size(2)][packetId(2)][ ... ]
public sealed override int OnRecv(ArraySegment<byte> buffer)
{
int processLen = 0;
while (true)
{
// 최소한 헤더는 파싱할 수 있는지 확인
if (buffer.Count < HeaderSize)
break;
// 패킷이 완전체로 도착했는지 확인
ushort dataSize = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
if (buffer.Count < dataSize)
break;
// 여기까지 왔으면 패킷 조립 가능
OnRecvPacket(new ArraySegment<byte>(buffer.Array, buffer.Offset, dataSize));
processLen += dataSize;
buffer = new ArraySegment<byte>(buffer.Array, buffer.Offset + dataSize, buffer.Count - dataSize);
}
return processLen;
}
public abstract void OnRecvPacket(ArraySegment<byte> buffer);
}
기존의 OnRecv함수는 sealed override를 통해 받은 패킷을 파싱하는데 사용하였다.
while문 안에서 패킷 조립이 가능한 곳까지 오면 OnRecvPacket 함수를 실행하도록 하였다.
이후 buffer를 다음 패킷 지점까지 옮겨 작업할 수 있도록 하였다.
public override void OnRecvPacket(ArraySegment<byte> buffer)
{
ushort size = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
ushort id = BitConverter.ToUInt16(buffer.Array, buffer.Offset + 2);
Console.WriteLine($"RecvPacketId : {id}, Size {size}");
}
받은 패킷을 처리하는 OnRecvPacket함수이다.
받은 패킷의 사이즈와 id를 출력하도록 하였다.
class GameSession : Session
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected {endPoint}");
Packet packet = new Packet() { size = 4, packetId = 7 };
// 보낸다
for (int i = 0; i < 5; i++)
{
ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
byte[] buffer = BitConverter.GetBytes(packet.size);
byte[] buffer2 = BitConverter.GetBytes(packet.packetId);
Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
ArraySegment<byte> sendBuff = SendBufferHelper.Close(packet.size);
Send(sendBuff);
}
}
사이즈 4, 아이디는 7의 내용을 담은 패킷을 생성하여 서버로 전송하였다.
서버에서 받은 패킷의 내용을 잘 받았음을 확인하였다.