From 7b58ca03383c3416ed9a11bc6442281ac073e1be Mon Sep 17 00:00:00 2001 From: "derek.holloway" Date: Wed, 1 Jul 2026 20:30:05 -0700 Subject: [PATCH] Shrink packet header size --- MistoxServer/Client/TCPClient.cs | 4 +- MistoxServer/Client/UDPClient.cs | 25 ++----- MistoxServer/Interface/ClientInterface.cs | 2 +- MistoxServer/Interface/Interface.cs | 17 ++--- MistoxServer/Interface/ServerInterface.cs | 12 ++-- MistoxServer/Server/ServerListener.cs | 6 +- MistoxServer/Server/TCPServer.cs | 23 ++---- MistoxServer/mExtensions.cs | 88 ++++++++--------------- MistoxServer/mPacket/DataPacket.cs | 65 +++++++++++++++++ MistoxServer/mPacket/PacketAttribute.cs | 13 ++++ 10 files changed, 140 insertions(+), 115 deletions(-) create mode 100644 MistoxServer/mPacket/DataPacket.cs create mode 100644 MistoxServer/mPacket/PacketAttribute.cs diff --git a/MistoxServer/Client/TCPClient.cs b/MistoxServer/Client/TCPClient.cs index 81cd9be..5b0a4bf 100644 --- a/MistoxServer/Client/TCPClient.cs +++ b/MistoxServer/Client/TCPClient.cs @@ -57,8 +57,8 @@ namespace MistoxServer.Client { } } - public async Task Send(Packet packet) { - byte[] data = mSerialize.PacketSerialize( packet ); + public async Task Send(T packet) { + byte[] data = DataPacket.Serialize( packet ); await Server.GetStream().WriteAsync( data, 0, data.Length ); } diff --git a/MistoxServer/Client/UDPClient.cs b/MistoxServer/Client/UDPClient.cs index 5ad6c25..cedb87e 100644 --- a/MistoxServer/Client/UDPClient.cs +++ b/MistoxServer/Client/UDPClient.cs @@ -10,20 +10,18 @@ namespace MistoxServer.Client { public class mUDPClient : IDisposable { public event EventHandler onReceived; - ServerMode Mode; Socket udpClient; bool Alive; int Port; - public mUDPClient( IPEndPoint ServerAddress, ServerMode mode ) { + public mUDPClient( IPEndPoint ServerAddress ) { udpClient = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp ); udpClient.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true ); udpClient.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, 128 ); udpClient.Bind( new IPEndPoint( IPAddress.Any, ServerAddress.Port ) ); Alive = true; Port = ServerAddress.Port; - Mode = mode; Thread Client = new Thread(async() => { await ReceiveThread(); }); Client.Start(); } @@ -33,13 +31,9 @@ namespace MistoxServer.Client { try { byte[] buffer = new byte[1024]; int bytesRead = await udpClient.ReceiveAsync( buffer ); - if (Mode == ServerMode.Passive) { - onReceived?.Invoke( buffer.Sub( 0, bytesRead ), new EventArgs() ); - } else if (Mode == ServerMode.Authoritative) { - dynamic data = mSerialize.uReceive( buffer.Sub(0, bytesRead) ); - if( data != null ) { - onReceived?.Invoke( data, new EventArgs() ); - } + dynamic data = mSerialize.uReceive( buffer.Sub(0, bytesRead) ); + if( data != null ) { + onReceived?.Invoke( data, new EventArgs() ); } } catch( Exception ) { @@ -47,14 +41,9 @@ namespace MistoxServer.Client { } } - public async Task Send( Packet Data, IPEndPoint remoteHost ) { - if (Mode == ServerMode.Authoritative) { - byte[] byteData = mSerialize.PacketSerialize( Data ); - await udpClient.SendToAsync( byteData, SocketFlags.None, new IPEndPoint( remoteHost.Address, Port ) ); - } else if (Mode == ServerMode.Passive) { - byte[] byteData = Data as byte[]; - await udpClient.SendToAsync( byteData, SocketFlags.None, new IPEndPoint( remoteHost.Address, Port ) ); - } + public async Task Send( T Data, IPEndPoint remoteHost ) { + byte[] byteData = DataPacket.Serialize( Data ); + await udpClient.SendToAsync( byteData, SocketFlags.None, new IPEndPoint( remoteHost.Address, Port ) ); } public void Dispose() { diff --git a/MistoxServer/Interface/ClientInterface.cs b/MistoxServer/Interface/ClientInterface.cs index f998080..e75c853 100644 --- a/MistoxServer/Interface/ClientInterface.cs +++ b/MistoxServer/Interface/ClientInterface.cs @@ -28,7 +28,7 @@ namespace MistoxServer { Console.WriteLine( "The client is initilized and trying to connect to the server at ip : " + mPEndPoint.Address ); // Make a UDP connection to the server try { - FastUpdate = new mUDPClient( mPEndPoint, ServerMode.Authoritative ); + FastUpdate = new mUDPClient( mPEndPoint ); FastUpdate.onReceived += (object o, EventArgs e) => { onFastReceive?.Invoke( o, e ); }; } catch( Exception e ) { Console.WriteLine( "An error has occured with the connection to the server. Error { " ); diff --git a/MistoxServer/Interface/Interface.cs b/MistoxServer/Interface/Interface.cs index e8b2648..e5f6c9f 100644 --- a/MistoxServer/Interface/Interface.cs +++ b/MistoxServer/Interface/Interface.cs @@ -3,12 +3,15 @@ using System.Net; using System.Threading.Tasks; namespace MistoxServer { - public partial class mServer { - public static IMistoxServer newServer(int port, ServerMode mode) { - return new ServerInterface(port, mode); + public class mServer { + + public static IMistoxServer newServer(int port) { + DataPacket.BuildNetworkPacketList(); + return new ServerInterface(port); } public static IMistoxServer newClient(string ServerIPOrHostName, int Port) { + DataPacket.BuildNetworkPacketList(); int index = 0; IPAddress[] remoteAddress = Dns.GetHostAddresses(ServerIPOrHostName); for( int i=0; i< remoteAddress.Length; i++ ) { @@ -24,17 +27,16 @@ namespace MistoxServer { return null; } } + } public interface IMistoxServer { - public event EventHandler onConnected; public event EventHandler onSlowReceive; public event EventHandler onFastReceive; public event EventHandler onDisconnected; public Task Send(Packet data, SendType speed); - } public enum SendType { @@ -42,9 +44,4 @@ namespace MistoxServer { FastUpdate } - public enum ServerMode { - Passive, - Authoritative - } - } diff --git a/MistoxServer/Interface/ServerInterface.cs b/MistoxServer/Interface/ServerInterface.cs index 98b4bc6..67fabcb 100644 --- a/MistoxServer/Interface/ServerInterface.cs +++ b/MistoxServer/Interface/ServerInterface.cs @@ -17,21 +17,23 @@ namespace MistoxServer { public event EventHandler onFastReceive; public event EventHandler onDisconnected; - public ServerInterface( int port, ServerMode mode ) { - FastUpdateServer = new mUDPClient( new IPEndPoint( IPAddress.IPv6Any, port ), mode ); - SlowUpdateServer = new mTCPListener( port, mode ); + public ServerInterface( int port ) { + // Initilize the server listening connections + SlowUpdateServer = new mTCPListener( port ); SlowUpdateServer.onConnected += OnConnected; - FastUpdateServer.onReceived += ( object o, EventArgs e ) => { onFastReceive?.Invoke( o, e ); }; SlowUpdateServer.onDisconnected += OnDisconnected; + FastUpdateServer = new mUDPClient( new IPEndPoint( IPAddress.Any, port ) ); + FastUpdateServer.onReceived += ( object o, EventArgs e ) => { onFastReceive?.Invoke( o, e ); }; + Console.WriteLine( "The Server is initilized and waiting for clients to connect at port : " + port ); } void OnConnected( object sender, EventArgs e ) { Connection user = (Connection)sender; onConnected?.Invoke( sender, e ); - user.slowClient.onReceived+= ( object o, EventArgs e ) => { onSlowReceive?.Invoke( o, e ); }; + user.slowClient.onReceived += ( object o, EventArgs e ) => { onSlowReceive?.Invoke( o, e ); }; user.slowClient.onDisconnected += OnDisconnected; Connections.Add( user ); } diff --git a/MistoxServer/Server/ServerListener.cs b/MistoxServer/Server/ServerListener.cs index b573ca3..9fdba59 100644 --- a/MistoxServer/Server/ServerListener.cs +++ b/MistoxServer/Server/ServerListener.cs @@ -14,14 +14,12 @@ namespace MistoxServer.Server { public event EventHandler onReceive; TcpListener Listener; - ServerMode ServerMode; bool Alive; int port; - public mTCPListener( int Port, ServerMode mode ) { + public mTCPListener( int Port ) { port = Port; Alive = true; - ServerMode = mode; Thread ConnectionThread = new Thread(async () => await ListenerThread() ); ConnectionThread.Start(); } @@ -33,7 +31,7 @@ namespace MistoxServer.Server { TcpClient client = await Listener.AcceptTcpClientAsync(); Connection user = new Connection(){ - slowClient = new mTCPServer(client, ServerMode), + slowClient = new mTCPServer( client ), fastClient = new IPEndPoint( ((IPEndPoint)client.Client.RemoteEndPoint).Address, port ) }; diff --git a/MistoxServer/Server/TCPServer.cs b/MistoxServer/Server/TCPServer.cs index 607061b..4df6784 100644 --- a/MistoxServer/Server/TCPServer.cs +++ b/MistoxServer/Server/TCPServer.cs @@ -5,15 +5,13 @@ using System.Threading.Tasks; namespace MistoxServer.Server { public class mTCPServer : IDisposable { public TcpClient slowClient; - ServerMode Mode; public event EventHandler onReceived; public event EventHandler onDisconnected; - public mTCPServer( TcpClient client, ServerMode mode ) { + public mTCPServer( TcpClient client ) { slowClient = client; slowClient.Client.NoDelay = true; - Mode = mode; } bool Alive = true; @@ -24,13 +22,9 @@ namespace MistoxServer.Server { byte[] StreamData = new byte[1024]; int bytesRead = await slowClient.GetStream().ReadAsync(StreamData, 0, StreamData.Length); if( bytesRead > 0 ) { - if ( Mode == ServerMode.Passive) { - onReceived?.Invoke( StreamData.Sub( 0, bytesRead ), new EventArgs() ); - } else if ( Mode == ServerMode.Authoritative) { - dynamic data = mSerialize.tReceive( StreamData.Sub( 0, bytesRead ) ); - if( data != null ) { - onReceived?.Invoke( data, new EventArgs() ); - } + dynamic data = mSerialize.tReceive( StreamData.Sub( 0, bytesRead ) ); + if( data != null ) { + onReceived?.Invoke( data, new EventArgs() ); } } } catch( Exception ) { @@ -42,13 +36,8 @@ namespace MistoxServer.Server { } public async Task Send( T packet ) { - if( Mode == ServerMode.Authoritative ) { - byte[] byteData = mSerialize.PacketSerialize( packet ); - await slowClient.GetStream().WriteAsync( byteData, 0, byteData.Length ); - } else if( Mode == ServerMode.Passive ) { - byte[] byteData = packet as byte[]; - await slowClient.GetStream().WriteAsync( byteData, 0, byteData.Length ); - } + byte[] byteData = DataPacket.Serialize( packet ); + await slowClient.GetStream().WriteAsync( byteData, 0, byteData.Length ); } public void Dispose() { diff --git a/MistoxServer/mExtensions.cs b/MistoxServer/mExtensions.cs index 9d8ead8..d0b02ff 100644 --- a/MistoxServer/mExtensions.cs +++ b/MistoxServer/mExtensions.cs @@ -1,7 +1,4 @@ using System; -using System.IO; -using System.Text; -using MsgPack.Serialization; namespace MistoxServer { @@ -18,74 +15,49 @@ namespace MistoxServer { Array.Copy( data, index, result, 0, length ); return result; } - } public class mSerialize { - public static byte[] PacketSerialize( T Packet ) { - MessagePackSerializer serializer = MessagePackSerializer.Get(); - using( MemoryStream stream = new MemoryStream() ) { - serializer.Pack( stream, Packet ); - byte[] typename = Encoding.UTF8.GetBytes(typeof(T).FullName + "," + typeof(T).Assembly.FullName); - byte[] typelength = BitConverter.GetBytes(typename.Length); - byte[] packetdata = stream.ToArray(); - byte[] paketlength = BitConverter.GetBytes(packetdata.Length); - return typelength.Join( typename ).Join( paketlength ).Join( packetdata ); - } - } - public static object PacketDeserialize( string typeData, byte[] Data ) { - Type type = Type.GetType( typeData ); - MessagePackSerializer Serilizer = MessagePackSerializer.Get(type); - - using( MemoryStream ms = new MemoryStream( Data ) ) { - return (object)Serilizer.Unpack( ms ); - } - } - - static byte[] TBufferedData = new byte[0]; + static byte[] TBufferedData = []; public static dynamic tReceive( byte [] BytesRead ) { + // Append the new data onto the old data TBufferedData = TBufferedData.Join( BytesRead ); - if( TBufferedData.Length > 4 ) { - int typeLength = BitConverter.ToInt32( TBufferedData.Sub(0, 4) ); - if( TBufferedData.Length > (8 + typeLength) ) { - int dataLength = BitConverter.ToInt32( TBufferedData.Sub( typeLength + 4, 4 ) ); - int TotalLength = 8 + typeLength + dataLength; - if ( TBufferedData.Length >= TotalLength ) { - string typeData = Encoding.UTF8.GetString( TBufferedData.Sub(4, typeLength) ); - if ( typeData.Substring(0, 13) != "System.Object" ) { - byte[] dataBytes = TBufferedData.Sub( (typeLength + 8), dataLength ); - dynamic data = mSerialize.PacketDeserialize( typeData, dataBytes ); - TBufferedData = TBufferedData.Sub( TotalLength, TBufferedData.Length - TotalLength ); - return data; - } else { - TBufferedData = TBufferedData.Sub( TotalLength, TBufferedData.Length - TotalLength ); - } - } + + // If the total of the data is bigger than the header + if( TBufferedData.Length > DataPacket.HeaderLength ) { + DataPacket packet = new DataPacket() { + PacketType = BytesRead[0], + DataLength = BitConverter.ToUInt16( BytesRead.Sub(1,2) ) + }; + + // If the total of the data is bigger then the whole packet + if (TBufferedData.Length > DataPacket.HeaderLength + packet.DataLength) { + packet.PacketData = TBufferedData.Sub( DataPacket.HeaderLength, packet.DataLength ); + TBufferedData = TBufferedData.Sub( DataPacket.HeaderLength, TBufferedData.Length - ( DataPacket.HeaderLength + packet.DataLength ) ); + return packet.Deserialize(); } } return null; } - static byte[] UBufferedData = new byte[0]; + static byte[] UBufferedData = []; public static dynamic uReceive( byte [] BytesRead ) { + // Append the new data onto the old data UBufferedData = UBufferedData.Join( BytesRead ); - if( UBufferedData.Length > 4 ) { - int typeLength = BitConverter.ToInt32( UBufferedData.Sub(0, 4) ); - if( UBufferedData.Length > (8 + typeLength) ) { - int dataLength = BitConverter.ToInt32( UBufferedData.Sub( typeLength + 4, 4 ) ); - int TotalLength = 8 + typeLength + dataLength; - if( UBufferedData.Length >= TotalLength ) { - string typeData = Encoding.UTF8.GetString( UBufferedData.Sub(4, typeLength) ); - if( typeData.Substring( 0, 13 ) != "System.Object" ) { - byte[] dataBytes = UBufferedData.Sub( (typeLength + 8), dataLength ); - dynamic data = mSerialize.PacketDeserialize( typeData, dataBytes ); - UBufferedData = UBufferedData.Sub( TotalLength, UBufferedData.Length - TotalLength ); - return data; - } else { - UBufferedData = UBufferedData.Sub( TotalLength, UBufferedData.Length - TotalLength ); - } - } + + // If the total of the data is bigger than the header + if( UBufferedData.Length > DataPacket.HeaderLength ) { + DataPacket packet = new DataPacket() { + PacketType = BytesRead[0], + DataLength = BitConverter.ToUInt16( BytesRead.Sub(1,2) ) + }; + + // If the total of the data is bigger then the whole packet + if (UBufferedData.Length > DataPacket.HeaderLength + packet.DataLength) { + packet.PacketData = UBufferedData.Sub( DataPacket.HeaderLength, packet.DataLength ); + UBufferedData = UBufferedData.Sub( DataPacket.HeaderLength, UBufferedData.Length - ( DataPacket.HeaderLength + packet.DataLength ) ); + return packet.Deserialize(); } } return null; diff --git a/MistoxServer/mPacket/DataPacket.cs b/MistoxServer/mPacket/DataPacket.cs new file mode 100644 index 0000000..05b0b70 --- /dev/null +++ b/MistoxServer/mPacket/DataPacket.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using MistoxServer.Attributes; +using MsgPack.Serialization; + +namespace MistoxServer { + public class DataPacket { + + // The length of the packet header in bytes + public static readonly int HeaderLength = 3; + + // Data Packet Properties + public byte PacketType { get; set; } = 0x00; + public ushort DataLength { get; set; } = 0; + public byte[] PacketData { get; set; } = []; + + + + + // 8b. 16b. ? + // Data Packet [ Type | DataLength | Data ] + + // Helper classes + public static byte[] Serialize( T Object ) { + mPacket attribute = typeof(T).GetCustomAttribute(false); + DataPacket packet = new DataPacket(); + if (attribute != null) { + using ( MemoryStream stream = new MemoryStream() ) { + MessagePackSerializer serializer = MessagePackSerializer.Get(); + serializer.Pack( stream, Object ); + packet.PacketData = stream.ToArray(); + packet.DataLength = (ushort)packet.PacketData.Length; + return new byte[]{ packet.PacketType }.Join( BitConverter.GetBytes( packet.DataLength )).Join(packet.PacketData); + } + } + throw new Exception( "The datastructure " + typeof(T).Name + " is not an mPacket" ); + } + + public object Deserialize() { + Type type = Type.GetType( NetworkPackets[PacketType] ); + MessagePackSerializer Serilizer = MessagePackSerializer.Get(type); + using( MemoryStream ms = new MemoryStream( PacketData ) ) { + return Serilizer.Unpack( ms ); + } + } + + + + + // Fills out the NetworkPacket Lookup Dictionary + public static readonly Dictionary NetworkPackets = new(); + public static void BuildNetworkPacketList() { + Type[] allClasses = Assembly.GetExecutingAssembly().GetTypes(); + foreach( Type cur in allClasses) { + mPacket attribute = cur.GetCustomAttribute(false); + if (attribute != null) { + NetworkPackets[attribute.ID] = cur.FullName + "," + cur.Assembly.FullName; + } + } + } + + } +} \ No newline at end of file diff --git a/MistoxServer/mPacket/PacketAttribute.cs b/MistoxServer/mPacket/PacketAttribute.cs new file mode 100644 index 0000000..298b4e1 --- /dev/null +++ b/MistoxServer/mPacket/PacketAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace MistoxServer.Attributes { + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + public sealed class mPacket : Attribute { + public byte ID { get; } + public mPacket(byte id) { + ID = id; + } + } + +} \ No newline at end of file