Packet Serialization
패킷 직렬화
간단히 말해, 서버와 클라이언트간의 소통을 패킷으로 할건데,
보내기 전에 압축해서 보낸다고 생각하면 된다.
메모리상의 인스턴스로 존재하는 것을 압축해서 버퍼안에 밀어 넣는 것이라 생각하자.
Client 프로젝트에서 Server 와 통신하기 위한 ServerSession 클래스
namespace DummyClient
{
class Packet //패킷 헤더
{
public ushort size;
public ushort packetId;
}
class PlayerInfoReq : Packet
{
public long playerId;
}
class PlayerInfoOk : Packet
{
public int hp;
public int attack;
}
public enum PacketID
{
PlayerInfoReq = 1,
PlayerInfoOk = 2,
}
class ServerSession : Session
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected !{endPoint}");
PlayerInfoReq packet = new PlayerInfoReq() {packetId = (ushort)PacketID.PlayerInfoReq, playerId = 1001};
//보낸다
//for (int i = 0; i < 5; i++)
{
ArraySegment<byte> s = SendBufferHelper.Open(4096);
ushort count = 0;
bool success = true;
// &= (and연산) 중간에 한번이라도 계산에 실패하면 false를 반환
// 그럼 TryWriteBytes가 실패하는 경우는 ?
// 애당초 2바이트짜리 크기인데 넣어주는
//packet.size의 부분이 8바이트 짜리면 공간이 모자라서 실패
//success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), packet.size);
count += 2;
success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.packetId);
count += 2;
success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.playerId);
count += 8;
//우리가 pakcet.size는 다 추가한 후에서야 알 수있으니 마지막에 추가
success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), count);
//byte[] size = BitConverter.GetBytes(packet.size); // ushort 2바이트
//byte[] packetId = BitConverter.GetBytes(packet.packetId); // ushort 2바이트
//byte[] playerId = BitConverter.GetBytes(packet.playerId); // long 8바이트
ArraySegment<byte> sendBuff = SendBufferHelper.Close(count);
if(success)
Send(sendBuff);
}
}
public override void OnDisconnected(EndPoint endPoint)
{
Console.WriteLine($"OnDisconnected !{endPoint}");
}
public override int OnRecv(ArraySegment<byte> buffer)
{
string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
Console.WriteLine($"[From Server] {recvData}");
return buffer.Count;
}
public override void OnSend(int numOfBytes)
{
Console.WriteLine($"Transferred bytes : {numOfBytes}");
}
}
}
Server에서 Client값을 받는 ClientSession
namespace Server
{
class Packet //패킷 헤더
{
public ushort size;
public ushort packetId;
}
class PlayerInfoReq : Packet
{
public long plyareId;
}
class PlayerInfoOk : Packet
{
public int hp;
public int attack;
}
public enum PacketID
{
PlayerInfoReq = 1,
PlayerInfoOk = 2,
}
class ClientSession : PacketSession
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected !{endPoint}");
//OnRecvPacket이 잘오는지 확인하기 위해 잠시 주석처리
//Packet packet = new Packet() { size = 100, packetId = 10 };
//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(buffer.Length + buffer2.Length);
//Send(sendBuff);
Thread.Sleep(5000);
Disconnect();
}
public override void OnRecvPacket(ArraySegment<byte> buffer)
{
ushort count = 0;
ushort size = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
count += 2;
ushort id = BitConverter.ToUInt16(buffer.Array, buffer.Offset + count);
count += 2;
switch((PacketID)id)
{
case PacketID.PlayerInfoReq:
{
long playerId = BitConverter.ToInt64(buffer.Array, buffer.Offset + count);
count += 8;
Console.WriteLine($"PlayerInfoReq : {playerId} ");
}
break;
}
}
public override void OnDisconnected(EndPoint endPoint)
{
Console.WriteLine($"OnDisconnected !{endPoint}");
}
public override void OnSend(int numOfBytes)
{
Console.WriteLine($"Transferred bytes : {numOfBytes}");
}
}
}