지금까지 구현은 아래와 같이 되어있는데. 좀 더 현실적으로 바꿔보자
class Knight
{
public int hp;
public int attack;
}
class GameSession : Session
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"[OnConnected] {endPoint}");
Knight kinght = new Knight() { hp = 100, attack = 10 };
// 보내는 부분
ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
byte[] buffer = BitConverter.GetBytes(kinght.hp);
byte[] buffer2 = BitConverter.GetBytes(kinght.attack);
Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
ArraySegment<byte> sendBuffer = SendBufferHelper.Close(buffer.Length + buffer2.Length);
Send(sendBuffer);
Thread.Sleep(1000);
Disconnect();
}
// ...
class Packet
{
public int hp;
public int attack;
}
class GameSession : Session
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"[OnConnected] {endPoint}");
Packet packet = new Packet() { hp = 100, attack = 10 };
// 보내는 부분
ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);
byte[] buffer = BitConverter.GetBytes(packet.hp);
byte[] buffer2 = BitConverter.GetBytes(packet.attack);
Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
ArraySegment<byte> sendBuffer = SendBufferHelper.Close(buffer.Length + buffer2.Length);
Send(sendBuffer);
Thread.Sleep(1000);
Disconnect();
}
여기서 또 발생하는 문제가 TCP의 특성상 패킷이 한 번에 들어올수도 여러번에 나눠서 들어올 수 있다. -> 패킷의 ID를 정해서 다들어왔나 들어오지 않았나 판별하면 어떨까?
그런데 패킷 ID만 보고는 유동적으로 변하는 패킷의 사이즈(Ex) String)경우 알수 없으니 사이즈 정보 자체를 보내보자
class Packet
{
public ushort size;
public ushort packetId;
}
class LoginOkPacket : Packet
{
// ...
}
패킷을 파싱하는 Session을 별도로 만들어보자
public abstract class PacketSession : Session
{
public static readonly short HeaderSize = 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);
}
실제사용은
class Knight
{
public int hp;
public int attack;
}
class GameSession : PacketSession
{
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}");
}
class Packet
{
public int size;
public int packetId;
}
class GameSession : PacketSession
{
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> sendBuffer = SendBufferHelper.Close(packet.size);
Send(sendBuffer);
}
//Thread.Sleep(1000);
//Disconnect();
}