├── Demos ├── GameServer │ ├── Settings.cs │ ├── IPlayerService.cs │ ├── PlayerUpdatePacket.cs │ ├── PlayerService.cs │ ├── GameServer.csproj │ ├── PlayerUpdatePacketHandler.cs │ └── Program.cs ├── Demo.Common │ ├── BasicPacket.cs │ ├── Demo.Common.csproj │ └── BasicPacketHandler.cs ├── Demo.Middleware │ └── Demo.Middleware.csproj ├── Tutorial.Server │ ├── appSettings.json │ ├── ChatPacketHandler.cs │ ├── Tutorial.Server.csproj │ └── Program.cs ├── Tutorial.Common │ ├── ChatPacket.cs │ └── Tutorial.Common.csproj ├── Tutorial.Client │ ├── clientSettings.json │ ├── ClientChatPacketHandler.cs │ ├── Tutorial.Client.csproj │ └── GameClient.cs └── Demo.Basic │ ├── Demo.Basic.csproj │ └── Program.cs ├── Networker ├── Common │ ├── PacketHandlerModule.cs │ ├── AsyncUserToken.cs │ ├── Abstractions │ │ ├── ISender.cs │ │ ├── IPacketHandler.cs │ │ ├── IPacketHandlerModule.cs │ │ ├── IMiddlewareHandler.cs │ │ ├── IPacketHandlers.cs │ │ ├── IBuilderOptions.cs │ │ ├── IPacketSerialiser.cs │ │ ├── IPacketContext.cs │ │ ├── IBuilder.cs │ │ └── BuilderBase.cs │ ├── ClientSettings.cs │ ├── LoggingExtensions.cs │ ├── PacketSerialiserProvider.cs │ ├── PacketHandlerBase.cs │ ├── PacketHandlerModuleBase.cs │ ├── UdpSender.cs │ ├── TcpSender.cs │ ├── PacketHandlers.cs │ ├── ObjectPool.cs │ └── PacketContext.cs ├── Server │ ├── Abstractions │ │ ├── ITcpSocketListenerFactory.cs │ │ ├── IUdpSocketListenerFactory.cs │ │ ├── ITcpConnection.cs │ │ ├── IUdpSocketListener.cs │ │ ├── ISocketListener.cs │ │ ├── IBufferManager.cs │ │ ├── IUdpSocketSender.cs │ │ ├── ITcpSocketListener.cs │ │ ├── ITcpConnections.cs │ │ ├── IServerInformation.cs │ │ ├── IServerBuilder.cs │ │ ├── IServer.cs │ │ └── IServerPacketProcessor.cs │ ├── TcpConnection.cs │ ├── TcpConnectionConnectedEventArgs.cs │ ├── TcpConnectionDisconnectedEventArgs.cs │ ├── ServerInformationEventArgs.cs │ ├── ServerInformation.cs │ ├── ServerBuilderOptions.cs │ ├── DefaultTcpSocketListenerFactory.cs │ ├── UdpSocketSender.cs │ ├── BufferManager.cs │ ├── DefaultUdpSocketListenerFactory.cs │ ├── TcpConnections.cs │ ├── UdpClientListener.cs │ ├── UdpSocketListener.cs │ ├── ServerBuilder.cs │ ├── Server.cs │ ├── ServerPacketProcessor.cs │ └── TcpSocketListener.cs ├── ExampleSettings.json ├── DefaultFormatter │ ├── DefaultNetworkerPacketBase.cs │ ├── DefaultNetworkerFormatterExtension.cs │ └── DefaultNetworkerPacketSerialiser.cs ├── Client │ ├── Abstractions │ │ ├── IClientPacketProcessor.cs │ │ ├── IClientBuilder.cs │ │ ├── IClient.cs │ │ └── ConnectResult.cs │ ├── ClientBuilderOptions.cs │ ├── UdpClientSender.cs │ ├── ClientBuilder.cs │ ├── Client.cs │ └── ClientPacketProcessor.cs └── Networker.csproj ├── Extensions ├── Networker.Extensions.ProtobufNet │ ├── ProtoBufPacketBase.cs │ ├── Networker.Extensions.ProtobufNet.csproj │ ├── ProtoBufNetBuilderExtension.cs │ └── ProtoBufNetSerialiser.cs ├── Networker.Extensions.ZeroFormatter │ ├── ZeroFormatterPacketBase.cs │ ├── Networker.Extensions.ZeroFormatter.csproj │ ├── ZeroFormatterBuilderExtension.cs │ └── ZeroFormatterPacketSerialiser.cs ├── Networker.Extensions.Json │ ├── Networker.Extensions.Json.csproj │ ├── JsonBuilderExtensions.cs │ └── JsonSerialiser.cs └── Networker.Extensions.MessagePack │ ├── Networker.Extensions.MessagePack.csproj │ ├── MessagePackBuilderExtensions.cs │ └── MessagePackPacketSerialiser.cs ├── Tests ├── Networker.Tests.Json │ ├── Networker.Tests.Json.csproj │ └── Program.cs ├── Networker.Tests.ProtobufNet │ ├── Networker.Tests.ProtobufNet.csproj │ └── Program.cs ├── Networker.Tests.ZeroFormatter │ ├── Networker.Tests.ZeroFormatter.csproj │ └── Program.cs └── Networker.Tests.MessagePack │ ├── PingPacket.cs │ ├── Networker.Tests.MessagePack.csproj │ ├── PingPacketHandler.cs │ └── Program.cs ├── LICENSE ├── README.md ├── .gitignore └── Networker.sln /Demos/GameServer/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace GameServer 2 | { 3 | public class Settings 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Demos/GameServer/IPlayerService.cs: -------------------------------------------------------------------------------- 1 | namespace GameServer 2 | { 3 | public interface IPlayerService 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Demos/GameServer/PlayerUpdatePacket.cs: -------------------------------------------------------------------------------- 1 | namespace GameServer 2 | { 3 | public class PlayerUpdatePacket 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Demos/GameServer/PlayerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GameServer 4 | { 5 | public class PlayerService : IPlayerService { } 6 | } -------------------------------------------------------------------------------- /Networker/Common/PacketHandlerModule.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Common 2 | { 3 | public class PacketHandlerModule : PacketHandlerModuleBase 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Demos/Demo.Common/BasicPacket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Demo.Common 4 | { 5 | public class BasicPacket 6 | { 7 | public string StringData { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Networker/Common/AsyncUserToken.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace Networker.Common 4 | { 5 | internal class AsyncUserToken 6 | { 7 | public Socket Socket { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Demos/Demo.Middleware/Demo.Middleware.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ProtobufNet/ProtoBufPacketBase.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | 3 | namespace Networker.Extensions.ProtobufNet 4 | { 5 | [ProtoContract] 6 | public class ProtoBufPacketBase 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/ITcpSocketListenerFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Server.Abstractions 2 | { 3 | public interface ITcpSocketListenerFactory 4 | { 5 | ITcpSocketListener Create(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IUdpSocketListenerFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Server.Abstractions 2 | { 3 | public interface IUdpSocketListenerFactory 4 | { 5 | IUdpSocketListener Create(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Networker/Common/Abstractions/ISender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Networker.Common.Abstractions 4 | { 5 | public interface ISender 6 | { 7 | IPEndPoint EndPoint { get; } 8 | void Send(T packet); 9 | } 10 | } -------------------------------------------------------------------------------- /Networker/ExampleSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug" 5 | }, 6 | "Console": { 7 | "LogLevel": { 8 | "Default": "Debug" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Networker/Common/ClientSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Common 2 | { 3 | public class CommonSettings 4 | { 5 | public string Address { get; set; } 6 | public int? TcpPort { get; set; } 7 | public int? UdpPort { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ZeroFormatter/ZeroFormatterPacketBase.cs: -------------------------------------------------------------------------------- 1 | using ZeroFormatter; 2 | 3 | namespace Networker.Extensions.ZeroFormatter 4 | { 5 | [ZeroFormattable] 6 | public abstract class ZeroFormatterPacketBase 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/ITcpConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface ITcpConnection 6 | { 7 | Socket Socket { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Networker/DefaultFormatter/DefaultNetworkerPacketBase.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.DefaultFormatter 2 | { 3 | public abstract class DefaultNetworkerPacketBase 4 | { 5 | protected DefaultNetworkerPacketBase(byte[] packetBytes) 6 | { 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /Tests/Networker.Tests.Json/Networker.Tests.Json.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/Networker.Tests.Json/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Tests.Json 4 | { 5 | internal class Program 6 | { 7 | private static void Main(string[] args) 8 | { 9 | Console.WriteLine("Hello World!"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IPacketHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Networker.Common.Abstractions 4 | { 5 | public interface IPacketHandler 6 | { 7 | Task Handle(IPacketContext packetContext); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IUdpSocketListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface IUdpSocketListener : ISocketListener 6 | { 7 | IPEndPoint GetEndPoint(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/ISocketListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface ISocketListener 6 | { 7 | Socket GetSocket(); 8 | void Listen(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Networker.Tests.ProtobufNet/Networker.Tests.ProtobufNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/Networker.Tests.ProtobufNet/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Tests.ProtobufNet 4 | { 5 | internal class Program 6 | { 7 | private static void Main(string[] args) 8 | { 9 | Console.WriteLine("Hello World!"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Tests/Networker.Tests.ZeroFormatter/Networker.Tests.ZeroFormatter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/Networker.Tests.ZeroFormatter/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Tests.ZeroFormatter 4 | { 5 | internal class Program 6 | { 7 | private static void Main(string[] args) 8 | { 9 | Console.WriteLine("Hello World!"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IPacketHandlerModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Networker.Common.Abstractions 5 | { 6 | public interface IPacketHandlerModule 7 | { 8 | Dictionary GetPacketHandlers(); 9 | } 10 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IMiddlewareHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Networker.Common.Abstractions 5 | { 6 | public interface IMiddlewareHandler 7 | { 8 | Task Process(IPacketContext context, Action nextMiddleware); 9 | } 10 | } -------------------------------------------------------------------------------- /Demos/Demo.Common/Demo.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Demos/Tutorial.Server/appSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Networker": { 3 | "TcpPort": 1000, 4 | "UdpPort": 1001 5 | }, 6 | "Logging": { 7 | "LogLevel": { 8 | "Default": "Debug" 9 | }, 10 | "Console": { 11 | "LogLevel": { 12 | "Default": "Debug" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IPacketHandlers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Networker.Common.Abstractions 4 | { 5 | public interface IPacketHandlers 6 | { 7 | void Add(string name, IPacketHandler packetHandler); 8 | Dictionary GetPacketHandlers(); 9 | } 10 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Common/ChatPacket.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | 3 | namespace Tutorial.Common 4 | { 5 | [ProtoContract] 6 | public class ChatPacket 7 | { 8 | [ProtoMember(1)] 9 | public virtual string Name { get; set; } 10 | 11 | [ProtoMember(2)] 12 | public virtual string Message { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IBuilderOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Networker.Common.Abstractions 4 | { 5 | public interface IBuilderOptions 6 | { 7 | LogLevel LogLevel { get; set; } 8 | int PacketSizeBuffer { get; set; } 9 | int TcpPort { get; set; } 10 | int UdpPort { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IBufferManager.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface IBufferManager 6 | { 7 | void FreeBuffer(SocketAsyncEventArgs args); 8 | void InitBuffer(); 9 | bool SetBuffer(SocketAsyncEventArgs args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Networker/Common/LoggingExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Networker.Common 5 | { 6 | public static class LoggingExtensions 7 | { 8 | public static void Error(this ILogger logger, Exception exception) 9 | { 10 | logger.Log(LogLevel.Error, exception.ToString()); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Client/clientSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Networker": { 3 | "TcpPort": 1000, 4 | "UdpPort": 1001, 5 | "Address": "localhost" 6 | }, 7 | "Logging": { 8 | "LogLevel": { 9 | "Default": "Debug" 10 | }, 11 | "Console": { 12 | "LogLevel": { 13 | "Default": "Debug" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Networker/Common/PacketSerialiserProvider.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | 3 | namespace Networker.Common 4 | { 5 | public class PacketSerialiserProvider 6 | { 7 | public static IPacketSerialiser PacketSerialiser { get; set; } 8 | 9 | public static IPacketSerialiser Provide() 10 | { 11 | return PacketSerialiser; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IUdpSocketSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface IUdpSocketSender 6 | { 7 | void SendTo(byte[] packetBytes, IPEndPoint endpoint); 8 | void SendTo(T packet, IPEndPoint endpoint); 9 | void Broadcast(T packet); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Networker.Tests.MessagePack/PingPacket.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | using System; 3 | 4 | namespace Networker.Tests.MessagePack 5 | { 6 | [MessagePackObject] 7 | public class PingPacket 8 | { 9 | [Key(0)] 10 | public virtual DateTime Time { get; set; } 11 | 12 | public PingPacket(DateTime time) 13 | { 14 | Time = time; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Demos/Tutorial.Common/Tutorial.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Networker/Client/Abstractions/IClientPacketProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using Networker.Server.Abstractions; 3 | 4 | namespace Networker.Client.Abstractions 5 | { 6 | public interface IClientPacketProcessor 7 | { 8 | void Process(Socket socket); 9 | void Process(UdpReceiveResult data); 10 | void SetUdpSocketSender(IUdpSocketSender socketSender); 11 | } 12 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/ITcpSocketListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface ITcpSocketListener : ISocketListener 6 | { 7 | EventHandler ClientConnected { get; set; } 8 | EventHandler ClientDisconnected { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Networker/Server/TcpConnection.cs: -------------------------------------------------------------------------------- 1 | using Networker.Server.Abstractions; 2 | using System.Net.Sockets; 3 | 4 | namespace Networker.Server 5 | { 6 | public class TcpConnection : ITcpConnection 7 | { 8 | public Socket Socket { get; set; } 9 | 10 | public TcpConnection(Socket socket) 11 | { 12 | this.Socket = socket; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/ITcpConnections.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Sockets; 3 | 4 | namespace Networker.Server.Abstractions 5 | { 6 | public interface ITcpConnections 7 | { 8 | List GetConnections(); 9 | 10 | ITcpConnection Add(Socket connection); 11 | void Remove(ITcpConnection connection); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Networker/Server/TcpConnectionConnectedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Networker.Server.Abstractions; 3 | 4 | namespace Networker.Server 5 | { 6 | public class TcpConnectionConnectedEventArgs : EventArgs 7 | { 8 | public TcpConnectionConnectedEventArgs(ITcpConnection connection) 9 | { 10 | Connection = connection; 11 | } 12 | 13 | public ITcpConnection Connection { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /Networker/Server/TcpConnectionDisconnectedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Networker.Server.Abstractions; 3 | 4 | namespace Networker.Server 5 | { 6 | public class TcpConnectionDisconnectedEventArgs : EventArgs 7 | { 8 | public TcpConnectionDisconnectedEventArgs(ITcpConnection connection) 9 | { 10 | Connection = connection; 11 | } 12 | 13 | public ITcpConnection Connection { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IServerInformation.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Server.Abstractions 2 | { 3 | public interface IServerInformation 4 | { 5 | bool IsRunning { get; set; } 6 | 7 | int InvalidTcpPackets { get; set; } 8 | int ProcessedTcpPackets { get; set; } 9 | 10 | int InvalidUdpPackets { get; set; } 11 | int ProcessedUdpPackets { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Networker/Server/ServerInformationEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Server 4 | { 5 | public class ServerInformationEventArgs : EventArgs 6 | { 7 | public int InvalidTcpPackets { get; set; } 8 | public int InvalidUdpPackets { get; set; } 9 | public int ProcessedTcpPackets { get; set; } 10 | public int ProcessedUdpPackets { get; set; } 11 | public int TcpConnections { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IPacketSerialiser.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.Common.Abstractions 2 | { 3 | public interface IPacketSerialiser 4 | { 5 | bool CanReadLength { get; } 6 | bool CanReadName { get; } 7 | bool CanReadOffset { get; } 8 | T Deserialise(byte[] packetBytes); 9 | T Deserialise(byte[] packetBytes, int offset, int length); 10 | byte[] Package(string name, byte[] bytes); 11 | byte[] Serialise(T packet); 12 | } 13 | } -------------------------------------------------------------------------------- /Networker/Client/Abstractions/IClientBuilder.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | 3 | namespace Networker.Client.Abstractions 4 | { 5 | public interface IClientBuilder : IBuilder 6 | { 7 | T Build() 8 | where T : IClient; 9 | 10 | //Info 11 | IClientBuilder SetPacketBufferPoolSize(int size); 12 | 13 | IClientBuilder UseIp(string ip); 14 | 15 | //Udp 16 | IClientBuilder UseUdp(int port, int localPort); 17 | } 18 | } -------------------------------------------------------------------------------- /Networker/Server/ServerInformation.cs: -------------------------------------------------------------------------------- 1 | using Networker.Server.Abstractions; 2 | 3 | namespace Networker.Server 4 | { 5 | public class ServerInformation : IServerInformation 6 | { 7 | public bool IsRunning { get; set; } 8 | 9 | public int InvalidTcpPackets { get; set; } 10 | public int ProcessedTcpPackets { get; set; } 11 | 12 | public int ProcessedUdpPackets { get; set; } 13 | public int InvalidUdpPackets { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Networker/Common/PacketHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | using System.Threading.Tasks; 3 | 4 | namespace Networker.Common 5 | { 6 | public abstract class PacketHandlerBase : IPacketHandler 7 | where T : class 8 | { 9 | public async Task Handle(IPacketContext context) 10 | { 11 | await this.Process(context.Serialiser.Deserialise(context.PacketBytes), context); 12 | } 13 | 14 | public abstract Task Process(T packet, IPacketContext context); 15 | } 16 | } -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IPacketContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Networker.Common.Abstractions 4 | { 5 | public interface IPacketContext 6 | { 7 | Dictionary Data { get; set; } 8 | IPacketHandler Handler { get; set; } 9 | byte[] PacketBytes { get; set; } 10 | string PacketName { get; set; } 11 | ISender Sender { get; set; } 12 | IPacketSerialiser Serialiser { get; set; } 13 | 14 | T GetData(string name) 15 | where T : class; 16 | 17 | T GetPacket() 18 | where T : class; 19 | } 20 | } -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IServerBuilder.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface IServerBuilder : IBuilder 6 | { 7 | //Tcp 8 | IServerBuilder UseTcpSocketListener() 9 | where T : class, ITcpSocketListenerFactory; 10 | 11 | //Udp 12 | IServerBuilder UseUdpSocketListener() 13 | where T : class, IUdpSocketListenerFactory; 14 | 15 | //Info 16 | IServerBuilder SetMaximumConnections(int maxConnections); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Networker/Client/Abstractions/IClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | 4 | namespace Networker.Client.Abstractions 5 | { 6 | public interface IClient 7 | { 8 | EventHandler Connected { get; set; } 9 | EventHandler Disconnected { get; set; } 10 | 11 | void Send(T packet); 12 | // void Send(byte[] packet); 13 | 14 | void SendUdp(T packet); 15 | void SendUdp(byte[] packet); 16 | 17 | long Ping(int timeout = 10000); 18 | 19 | ConnectResult Connect(); 20 | 21 | void Stop(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Networker/Common/PacketHandlerModuleBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Networker.Common.Abstractions; 4 | 5 | namespace Networker.Common 6 | { 7 | public abstract class PacketHandlerModuleBase : IPacketHandlerModule 8 | { 9 | private readonly Dictionary _packetHandlers = new Dictionary(); 10 | 11 | public Dictionary GetPacketHandlers() 12 | { 13 | return _packetHandlers; 14 | } 15 | 16 | public void AddPacketHandler() 17 | { 18 | _packetHandlers.Add(typeof(TPacket), typeof(TPacketHandler)); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Networker/Common/UdpSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Networker.Common.Abstractions; 3 | using Networker.Server.Abstractions; 4 | 5 | namespace Networker.Common 6 | { 7 | public class UdpSender : ISender 8 | { 9 | private readonly IUdpSocketSender _socketSender; 10 | 11 | public UdpSender(IUdpSocketSender socketSender) 12 | { 13 | _socketSender = socketSender; 14 | } 15 | 16 | public EndPoint RemoteEndpoint { get; set; } 17 | 18 | public IPEndPoint EndPoint => RemoteEndpoint as IPEndPoint; 19 | 20 | public void Send(T packet) 21 | { 22 | _socketSender.SendTo(packet, EndPoint); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Demos/Demo.Common/BasicPacketHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Networker.Common; 4 | using Networker.Common.Abstractions; 5 | 6 | namespace Demo.Common 7 | { 8 | public class BasicPacketHandler : PacketHandlerBase 9 | { 10 | private readonly ILogger logger; 11 | 12 | public BasicPacketHandler(ILogger logger) 13 | { 14 | this.logger = logger; 15 | } 16 | 17 | public override async Task Process(BasicPacket packet, IPacketContext packetContext) 18 | { 19 | logger.LogDebug("Handling Basic Packet"); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Networker/Common/TcpSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | using Networker.Common.Abstractions; 4 | 5 | namespace Networker.Common 6 | { 7 | public class TcpSender : ISender 8 | { 9 | private readonly IPacketSerialiser _packetSerialiser; 10 | 11 | public TcpSender(IPacketSerialiser packetSerialiser) 12 | { 13 | _packetSerialiser = packetSerialiser; 14 | } 15 | 16 | public Socket Socket { get; set; } 17 | 18 | public IPEndPoint EndPoint => Socket.RemoteEndPoint as IPEndPoint; 19 | 20 | public void Send(T packet) 21 | { 22 | Socket.Send(_packetSerialiser.Serialise(packet)); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Demos/Demo.Basic/Demo.Basic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Networker/Common/PacketHandlers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Networker.Common.Abstractions; 3 | 4 | namespace Networker.Common 5 | { 6 | public class PacketHandlers : IPacketHandlers 7 | { 8 | private readonly Dictionary packetHandlers; 9 | 10 | public PacketHandlers() 11 | { 12 | packetHandlers = new Dictionary(); 13 | } 14 | 15 | public void Add(string name, IPacketHandler packetHandler) 16 | { 17 | packetHandlers.Add(name, packetHandler); 18 | } 19 | 20 | public Dictionary GetPacketHandlers() 21 | { 22 | return packetHandlers; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Demos/GameServer/GameServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Networker.Server.Abstractions 4 | { 5 | public interface IServer 6 | { 7 | IServerInformation Information { get; } 8 | 9 | ITcpConnections GetConnections(); 10 | 11 | EventHandler ServerInformationUpdated { get; set; } 12 | EventHandler ClientConnected { get; set; } 13 | EventHandler ClientDisconnected { get; set; } 14 | 15 | void Broadcast(T packet); 16 | // void Broadcast(byte[] packet); 17 | 18 | void Start(); 19 | void Stop(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Networker/Server/Abstractions/IServerPacketProcessor.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | using System.Threading.Tasks; 5 | 6 | namespace Networker.Server.Abstractions 7 | { 8 | public interface IServerPacketProcessor 9 | { 10 | void SetUdpSender(IUdpSocketSender sender); 11 | Task ProcessFromBuffer(ISender sender, byte[] buffer, int offset = 0, int length = 0, bool isTcp = true); 12 | void ProcessTcp(SocketAsyncEventArgs socketEvent); 13 | void ProcessUdp(SocketAsyncEventArgs socketEvent); 14 | void ProcessUdpFromBuffer(EndPoint sender, byte[] buffer, int offset = 0, int length = 0); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Networker/Server/ServerBuilderOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Common.Abstractions; 3 | 4 | namespace Networker.Server 5 | { 6 | public class ServerBuilderOptions : IBuilderOptions 7 | { 8 | public ServerBuilderOptions() 9 | { 10 | TcpMaxConnections = 100; 11 | UdpSocketObjectPoolSize = 10; 12 | PacketSizeBuffer = 5000; 13 | LogLevel = LogLevel.Error; 14 | } 15 | 16 | public int TcpMaxConnections { get; set; } 17 | public int UdpSocketObjectPoolSize { get; set; } 18 | 19 | public LogLevel LogLevel { get; set; } 20 | public int PacketSizeBuffer { get; set; } 21 | 22 | public int TcpPort { get; set; } 23 | public int UdpPort { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /Tests/Networker.Tests.MessagePack/Networker.Tests.MessagePack.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.Json/Networker.Extensions.Json.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | Networker.Extensions.Json 6 | Networker 7 | Networker 8 | 1.0.0.0 9 | The JSON packet formatter for Networker 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Demos/GameServer/PlayerUpdatePacketHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Networker.Common; 4 | using Networker.Common.Abstractions; 5 | 6 | namespace GameServer 7 | { 8 | public class PlayerUpdatePacketHandler : PacketHandlerBase 9 | { 10 | private readonly ILogger logger; 11 | 12 | public PlayerUpdatePacketHandler(ILogger logger) 13 | { 14 | this.logger = logger; 15 | } 16 | 17 | public override async Task Process(PlayerUpdatePacket packet, IPacketContext context) 18 | { 19 | this.logger.LogInformation("Wow some logging!"); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.MessagePack/Networker.Extensions.MessagePack.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | Networker 7 | Networker 8 | Networker 9 | 1.0.0.0 10 | The MessagePack packet formatter for Networker 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ProtobufNet/Networker.Extensions.ProtobufNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | Networker 7 | Networker 8 | Networker 9 | 1.0.0.0 10 | The protobuf-net packet formatter for Networker 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Networker/Common/ObjectPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Networker.Common 5 | { 6 | public class ObjectPool 7 | { 8 | private readonly Stack m_pool; 9 | 10 | public ObjectPool(int capacity) 11 | { 12 | Capacity = capacity; 13 | m_pool = new Stack(capacity); 14 | } 15 | 16 | public int Capacity { get; } 17 | 18 | public int Count => m_pool.Count; 19 | 20 | public T Pop() 21 | { 22 | lock (m_pool) 23 | { 24 | return m_pool.Pop(); 25 | } 26 | } 27 | 28 | public void Push(T item) 29 | { 30 | if (item == null) throw new ArgumentNullException("Items added to pool cannot be null"); 31 | 32 | lock (m_pool) 33 | { 34 | m_pool.Push(item); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Server/ChatPacketHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using Networker.Common; 4 | using Networker.Common.Abstractions; 5 | using Tutorial.Common; 6 | 7 | namespace Tutorial.Server 8 | { 9 | public class ChatPacketHandler : PacketHandlerBase 10 | { 11 | private readonly ILogger _logger; 12 | 13 | public ChatPacketHandler(ILogger logger) 14 | { 15 | _logger = logger; 16 | } 17 | 18 | public override async Task Process(ChatPacket packet, IPacketContext packetContext) 19 | { 20 | _logger.LogDebug("I received the chat message: " + packet.Message); 21 | 22 | packetContext.Sender.Send(new ChatPacket 23 | { 24 | Message = "Hey, I got your message!" 25 | }); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ZeroFormatter/Networker.Extensions.ZeroFormatter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | Networker.Extensions.ZeroFormatter 6 | Networker 7 | Networker 8 | 1.0.0.0 9 | The ZeroFormatter packet formatter for Networker 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Networker/Client/ClientBuilderOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Common.Abstractions; 3 | 4 | namespace Networker.Client 5 | { 6 | public class ClientBuilderOptions : IBuilderOptions 7 | { 8 | public int TcpPort { get; set; } 9 | public int UdpPort { get; set; } 10 | public string Ip { get; set; } 11 | public int UdpPortLocal { get; set; } 12 | public LogLevel LogLevel { get; set; } 13 | public int PacketSizeBuffer { get; set; } 14 | public int ObjectPoolSize { get; set; } 15 | 16 | public ClientBuilderOptions() 17 | { 18 | this.LogLevel = LogLevel.Error; 19 | this.PacketSizeBuffer = 3500; 20 | this.ObjectPoolSize = 200; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Tests/Networker.Tests.MessagePack/PingPacketHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Common; 3 | using Networker.Common.Abstractions; 4 | using System.Threading.Tasks; 5 | 6 | namespace Networker.Tests.MessagePack 7 | { 8 | public class PingPacketHandler : PacketHandlerBase 9 | { 10 | private readonly ILogger logger; 11 | 12 | public PingPacketHandler(ILogger logger, IPacketSerialiser serialiser) 13 | { 14 | this.logger = logger; 15 | } 16 | 17 | public override Task Process(PingPacket packet, IPacketContext context) 18 | { 19 | logger.LogDebug("Received a ping packet from " + context.Sender.EndPoint + " at " + packet.Time); 20 | return Task.CompletedTask; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Demos/Tutorial.Client/ClientChatPacketHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Logging; 6 | using Networker.Common; 7 | using Networker.Common.Abstractions; 8 | using Tutorial.Common; 9 | 10 | namespace Tutorial.Client 11 | { 12 | public class ClientChatPacketHandler : PacketHandlerBase 13 | { 14 | private readonly ILogger _logger; 15 | 16 | public ClientChatPacketHandler(ILogger logger) 17 | { 18 | _logger = logger; 19 | } 20 | 21 | public override async Task Process(ChatPacket packet, IPacketContext packetContext) 22 | { 23 | _logger.LogDebug("Client received the response packet: " + packet.Message); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Networker/Client/UdpClientSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Networker.Client.Abstractions; 3 | using Networker.Server.Abstractions; 4 | 5 | namespace Networker.Client 6 | { 7 | public class UdpClientSender : IUdpSocketSender 8 | { 9 | private readonly IClient _client; 10 | 11 | public UdpClientSender(IClient client, IClientPacketProcessor clientPacketProcessor) 12 | { 13 | _client = client; 14 | clientPacketProcessor.SetUdpSocketSender(this); 15 | } 16 | 17 | public void Broadcast(T packet) 18 | { 19 | _client.SendUdp(packet); 20 | } 21 | 22 | public void SendTo(byte[] packetBytes, IPEndPoint endpoint) 23 | { 24 | _client.SendUdp(packetBytes); 25 | } 26 | 27 | public void SendTo(T packet, IPEndPoint endpoint) 28 | { 29 | _client.SendUdp(packet); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Networker/Common/PacketContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Networker.Common.Abstractions; 3 | 4 | namespace Networker.Common 5 | { 6 | public class PacketContext : IPacketContext 7 | { 8 | public Dictionary Data { get; set; } 9 | public IPacketHandler Handler { get; set; } 10 | public byte[] PacketBytes { get; set; } 11 | public string PacketName { get; set; } 12 | public ISender Sender { get; set; } 13 | public IPacketSerialiser Serialiser { get; set; } 14 | 15 | public T GetData(string name) 16 | where T : class 17 | { 18 | if (Data.ContainsKey(name)) return Data[name] as T; 19 | 20 | return null; 21 | } 22 | 23 | public T GetPacket() 24 | where T : class 25 | { 26 | return Serialiser.Deserialise(PacketBytes); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Networker/Client/Abstractions/ConnectResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Networker.Client.Abstractions 5 | { 6 | public class ConnectResult 7 | { 8 | public bool Success { get; } 9 | 10 | public IEnumerable Errors { get; } 11 | 12 | public ConnectResult(bool success) 13 | { 14 | this.Success = success; 15 | this.Errors = null; 16 | } 17 | 18 | public ConnectResult(IEnumerable errors) 19 | { 20 | this.Success = errors.Count() == 0; 21 | this.Errors = errors; 22 | } 23 | 24 | public ConnectResult(params string[] errors) 25 | { 26 | this.Success = errors.Count() == 0; 27 | this.Errors = errors; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Networker/DefaultFormatter/DefaultNetworkerFormatterExtension.cs: -------------------------------------------------------------------------------- 1 | namespace Networker.DefaultFormatter 2 | { 3 | public static class DefaultNetworkerFormatterExtension 4 | { 5 | /* 6 | public static IServerBuilder UseDefaultFormatter(this IServerBuilder serverBuilder) 7 | { 8 | var serviceCollection = serverBuilder.GetServiceCollection(); 9 | serviceCollection.AddSingleton(); 10 | 11 | return serverBuilder; 12 | } 13 | 14 | public static IClientBuilder UseDefaultFormatter(this IClientBuilder clientBuilder) 15 | { 16 | var serviceCollection = clientBuilder.GetServiceCollection(); 17 | serviceCollection.AddSingleton(); 18 | return clientBuilder; 19 | }*/ 20 | } 21 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Client/Tutorial.Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Always 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.Json/JsonBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common.Abstractions; 4 | using Networker.Server.Abstractions; 5 | 6 | namespace Networker.Extensions.Json 7 | { 8 | public static class JsonBuilderExtensions 9 | { 10 | public static IServerBuilder UseJson(this IServerBuilder serverBuilder) 11 | { 12 | var serviceCollection = serverBuilder.GetServiceCollection(); 13 | serviceCollection.AddSingleton(); 14 | 15 | return serverBuilder; 16 | } 17 | 18 | public static IClientBuilder UseJson(this IClientBuilder clientBuilder) 19 | { 20 | var serviceCollection = clientBuilder.GetServiceCollection(); 21 | serviceCollection.AddSingleton(); 22 | return clientBuilder; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ProtobufNet/ProtoBufNetBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common.Abstractions; 4 | using Networker.Server.Abstractions; 5 | 6 | namespace Networker.Extensions.ProtobufNet 7 | { 8 | public static class ProtoBufNetBuilderExtension 9 | { 10 | public static IServerBuilder UseProtobufNet(this IServerBuilder serverBuilder) 11 | { 12 | var serviceCollection = serverBuilder.GetServiceCollection(); 13 | serviceCollection.AddSingleton(); 14 | 15 | return serverBuilder; 16 | } 17 | 18 | public static IClientBuilder UseProtobufNet(this IClientBuilder clientBuilder) 19 | { 20 | var serviceCollection = clientBuilder.GetServiceCollection(); 21 | serviceCollection.AddSingleton(); 22 | return clientBuilder; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.MessagePack/MessagePackBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common.Abstractions; 4 | using Networker.Server.Abstractions; 5 | 6 | namespace Networker.Extensions.MessagePack 7 | { 8 | public static class MessagePackBuilderExtensions 9 | { 10 | public static IServerBuilder UseMessagePack(this IServerBuilder serverBuilder) 11 | { 12 | var serviceCollection = serverBuilder.GetServiceCollection(); 13 | serviceCollection.AddSingleton(); 14 | return serverBuilder; 15 | } 16 | 17 | public static IClientBuilder UseMessagePack(this IClientBuilder clientBuilder) 18 | { 19 | var serviceCollection = clientBuilder.GetServiceCollection(); 20 | serviceCollection.AddSingleton(); 21 | return clientBuilder; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ZeroFormatter/ZeroFormatterBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common.Abstractions; 4 | using Networker.Server.Abstractions; 5 | 6 | namespace Networker.Extensions.ZeroFormatter 7 | { 8 | public static class ZeroFormatterBuilderExtension 9 | { 10 | public static IServerBuilder UseZeroFormatter(this IServerBuilder serverBuilder) 11 | { 12 | var serviceCollection = serverBuilder.GetServiceCollection(); 13 | serviceCollection.AddSingleton(); 14 | 15 | return serverBuilder; 16 | } 17 | 18 | public static IClientBuilder UseZeroFormatter(this IClientBuilder clientBuilder) 19 | { 20 | var serviceCollection = clientBuilder.GetServiceCollection(); 21 | serviceCollection.AddSingleton(); 22 | return clientBuilder; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Server/Tutorial.Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Always 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Demos/Tutorial.Client/GameClient.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.Logging; 3 | using Networker.Client; 4 | using Networker.Client.Abstractions; 5 | using Networker.Extensions.ProtobufNet; 6 | using Tutorial.Common; 7 | 8 | namespace Tutorial.Client 9 | { 10 | public class GameClient 11 | { 12 | public GameClient() 13 | { 14 | var config = new ConfigurationBuilder() 15 | .AddJsonFile("clientSettings.json", false, true) 16 | .Build(); 17 | 18 | var networkerSettings = config.GetSection("Networker"); 19 | 20 | Client = new ClientBuilder() 21 | .UseIp(networkerSettings.GetValue("Address")) 22 | .UseTcp(networkerSettings.GetValue("TcpPort")) 23 | .UseUdp(networkerSettings.GetValue("UdpPort")) 24 | .ConfigureLogging(loggingBuilder => 25 | { 26 | loggingBuilder.AddConfiguration(config.GetSection("Logging")); 27 | loggingBuilder.AddConsole(); 28 | }) 29 | .UseProtobufNet() 30 | .RegisterPacketHandler() 31 | .Build(); 32 | } 33 | 34 | public IClient Client { get; set; } 35 | } 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Networker/DefaultFormatter/DefaultNetworkerPacketSerialiser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.Serialization.Formatters.Binary; 4 | using Networker.Common.Abstractions; 5 | 6 | namespace Networker.DefaultFormatter 7 | { 8 | public class DefaultNetworkerPacketSerialiser : IPacketSerialiser 9 | { 10 | public bool CanReadLength => true; 11 | public bool CanReadName => true; 12 | 13 | public bool CanReadOffset => false; 14 | 15 | public T Deserialise(byte[] packetBytes) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | 20 | public T Deserialise(byte[] packetBytes, int offset, int length) 21 | { 22 | throw new NotImplementedException(); 23 | return (T) Activator.CreateInstance(typeof(T), packetBytes); 24 | } 25 | 26 | public byte[] Package(string name, byte[] bytes) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | public byte[] Serialise(T packet) 32 | { 33 | throw new NotImplementedException(); 34 | var bf = new BinaryFormatter(); 35 | using (var ms = new MemoryStream()) 36 | { 37 | bf.Serialize(ms, packet); 38 | return ms.ToArray(); 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Networker/Server/DefaultTcpSocketListenerFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Server.Abstractions; 3 | 4 | namespace Networker.Server 5 | { 6 | public class DefaultTcpSocketListenerFactory : ITcpSocketListenerFactory 7 | { 8 | private readonly IBufferManager bufferManager; 9 | private readonly ITcpConnections connections; 10 | private readonly ILogger logger; 11 | private readonly ServerBuilderOptions options; 12 | private readonly IServerPacketProcessor serverPacketProcessor; 13 | 14 | public DefaultTcpSocketListenerFactory(IServerPacketProcessor serverPacketProcessor, 15 | IBufferManager bufferManager, 16 | ILogger logger, 17 | ITcpConnections connections, 18 | ServerBuilderOptions options) 19 | { 20 | this.serverPacketProcessor = serverPacketProcessor; 21 | this.bufferManager = bufferManager; 22 | this.logger = logger; 23 | this.connections = connections; 24 | this.options = options; 25 | } 26 | 27 | public ITcpSocketListener Create() 28 | { 29 | return new TcpSocketListener(options, 30 | serverPacketProcessor, 31 | bufferManager, 32 | logger, 33 | connections); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Networker/Server/UdpSocketSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Networker.Common.Abstractions; 3 | using Networker.Server.Abstractions; 4 | 5 | namespace Networker.Server 6 | { 7 | public class UdpSocketSender : IUdpSocketSender 8 | { 9 | private readonly IPacketSerialiser _packetSerialiser; 10 | private readonly IUdpSocketListener _udpSocketListener; 11 | 12 | public UdpSocketSender(IUdpSocketListener udpSocketListener, IPacketSerialiser packetSerialiser) 13 | { 14 | _udpSocketListener = udpSocketListener; 15 | _packetSerialiser = packetSerialiser; 16 | } 17 | 18 | public void Broadcast(T packet) 19 | { 20 | var socket = _udpSocketListener.GetSocket(); 21 | var serialisedPacket = _packetSerialiser.Serialise(packet); 22 | socket.Send(serialisedPacket); 23 | } 24 | 25 | public void SendTo(byte[] packetBytes, IPEndPoint endpoint) 26 | { 27 | var socket = _udpSocketListener.GetSocket(); 28 | socket.SendTo(packetBytes, endpoint); 29 | } 30 | 31 | public void SendTo(T packet, IPEndPoint endpoint) 32 | { 33 | var socket = _udpSocketListener.GetSocket(); 34 | var serialisedPacket = _packetSerialiser.Serialise(packet); 35 | 36 | socket.SendTo(serialisedPacket, endpoint); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Tests/Networker.Tests.MessagePack/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Client; 3 | using Networker.Extensions.MessagePack; 4 | using Networker.Server; 5 | using System; 6 | using System.Threading; 7 | 8 | namespace Networker.Tests.MessagePack 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | var server = new ServerBuilder(). 15 | UseTcp(1000). 16 | RegisterPacketHandler(). 17 | UseMessagePack(). 18 | ConfigureLogging(loggingBuilder => 19 | { 20 | loggingBuilder.AddConsole(); 21 | loggingBuilder.SetMinimumLevel(LogLevel.Debug); 22 | }). 23 | Build(); 24 | 25 | server.Start(); 26 | 27 | var client = new ClientBuilder(). 28 | UseIp("127.0.0.1"). 29 | UseTcp(1000). 30 | UseMessagePack(). 31 | Build(); 32 | 33 | client.Connect(); 34 | 35 | for (int i = 0; i < 10; i++) 36 | { 37 | client.Send(new PingPacket(DateTime.Now)); 38 | Thread.Sleep(1000); 39 | } 40 | 41 | Console.WriteLine("Done. Press any key to continue..."); 42 | 43 | Console.ReadLine(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Demos/Demo.Basic/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Demo.Common; 5 | using Microsoft.Extensions.Logging; 6 | using Networker.Client; 7 | using Networker.Extensions.Json; 8 | using Networker.Server; 9 | 10 | namespace Demo.Basic 11 | { 12 | internal class Program 13 | { 14 | private static void Main(string[] args) 15 | { 16 | var server = new ServerBuilder().UseTcp(1000) 17 | .UseUdp(5000) 18 | .UseJson() 19 | .ConfigureLogging(loggingBuilder => 20 | { 21 | loggingBuilder.AddConsole(); 22 | loggingBuilder.SetMinimumLevel( 23 | LogLevel.Debug); 24 | }) 25 | .RegisterPacketHandler() 26 | .Build(); 27 | 28 | server.Start(); 29 | 30 | try 31 | { 32 | var client = new ClientBuilder().UseIp("127.0.0.1") 33 | .UseTcp(1000) 34 | .UseUdp(5000) 35 | .UseJson() 36 | .Build(); 37 | 38 | client.Connect(); 39 | 40 | Task.Factory.StartNew(() => 41 | { 42 | while (true) 43 | { 44 | client.Send(new BasicPacket()); 45 | Thread.Sleep(1000); 46 | } 47 | }); 48 | } 49 | catch (Exception e) 50 | { 51 | Console.WriteLine(e); 52 | } 53 | 54 | Console.ReadLine(); 55 | Console.ReadLine(); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Networker/Server/BufferManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Sockets; 3 | using Networker.Server.Abstractions; 4 | 5 | namespace Networker.Server 6 | { 7 | public class BufferManager : IBufferManager 8 | { 9 | private readonly int m_bufferSize; 10 | private readonly Stack m_freeIndexPool; 11 | private readonly int m_numBytes; 12 | private byte[] m_buffer; 13 | private int m_currentIndex; 14 | 15 | public BufferManager(int totalBytes, int bufferSize) 16 | { 17 | m_numBytes = totalBytes; 18 | m_currentIndex = 0; 19 | m_bufferSize = bufferSize; 20 | m_freeIndexPool = new Stack(); 21 | } 22 | 23 | public void FreeBuffer(SocketAsyncEventArgs args) 24 | { 25 | m_freeIndexPool.Push(args.Offset); 26 | args.SetBuffer(null, 0, 0); 27 | } 28 | 29 | public void InitBuffer() 30 | { 31 | m_buffer = new byte[m_numBytes]; 32 | } 33 | 34 | public bool SetBuffer(SocketAsyncEventArgs args) 35 | { 36 | if (m_freeIndexPool.Count > 0) 37 | { 38 | args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize); 39 | } 40 | else 41 | { 42 | if (m_numBytes - m_bufferSize < m_currentIndex) return false; 43 | 44 | args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize); 45 | m_currentIndex += m_bufferSize; 46 | } 47 | 48 | return true; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Networker/Server/DefaultUdpSocketListenerFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Server.Abstractions; 3 | 4 | namespace Networker.Server 5 | { 6 | public class DefaultUdpSocketListenerFactory : IUdpSocketListenerFactory 7 | { 8 | private readonly ILogger logger; 9 | private readonly ServerBuilderOptions options; 10 | private readonly IServerInformation serverInformation; 11 | private readonly IServerPacketProcessor serverPacketProcessor; 12 | private IUdpSocketListener _clientListener; 13 | 14 | public DefaultUdpSocketListenerFactory(ServerBuilderOptions options, 15 | ILogger logger, 16 | IServerPacketProcessor serverPacketProcessor, 17 | IServerInformation serverInformation) 18 | { 19 | this.options = options; 20 | this.logger = logger; 21 | this.serverPacketProcessor = serverPacketProcessor; 22 | this.serverInformation = serverInformation; 23 | } 24 | 25 | public IUdpSocketListener Create() 26 | { 27 | /*return new UdpSocketListener(this.options, 28 | this.logger, 29 | this.serverPacketProcessor, 30 | this.bufferManager);*/ 31 | 32 | return _clientListener ?? (_clientListener = new UdpClientListener(options, 33 | logger, 34 | serverPacketProcessor, 35 | serverInformation)); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.Json/JsonSerialiser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using Networker.Common.Abstractions; 4 | using Utf8Json; 5 | 6 | namespace Networker.Extensions.Json 7 | { 8 | public class JsonSerialiser : IPacketSerialiser 9 | { 10 | public bool CanReadLength => true; 11 | public bool CanReadName => true; 12 | 13 | public bool CanReadOffset => false; 14 | 15 | public T Deserialise(byte[] packetBytes) 16 | { 17 | return JsonSerializer.Deserialize(packetBytes); 18 | } 19 | 20 | public T Deserialise(byte[] packetBytes, int offset, int length) 21 | { 22 | return default(T); 23 | } 24 | 25 | public byte[] Package(string name, byte[] bytes) 26 | { 27 | return new byte[] { }; 28 | } 29 | 30 | public byte[] Serialise(T packet) 31 | { 32 | using (var memoryStream = new MemoryStream()) 33 | { 34 | using (var binaryWriter = new BinaryWriter(memoryStream)) 35 | { 36 | var nameBytes = Encoding.ASCII.GetBytes(typeof(T).Name); 37 | var serialised = JsonSerializer.Serialize(packet); 38 | binaryWriter.Write(nameBytes.Length); 39 | binaryWriter.Write(serialised.Length); 40 | binaryWriter.Write(nameBytes); 41 | binaryWriter.Write(serialised); 42 | } 43 | 44 | var packetBytes = memoryStream.ToArray(); 45 | return packetBytes; 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Demos/Tutorial.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.Logging; 5 | using Networker.Extensions.ProtobufNet; 6 | using Networker.Server; 7 | using Tutorial.Client; 8 | using Tutorial.Common; 9 | 10 | namespace Tutorial.Server 11 | { 12 | class Program 13 | { 14 | static void Main(string[] args) 15 | { 16 | IConfiguration config = new ConfigurationBuilder() 17 | .AddJsonFile("appsettings.json", false, true) 18 | .Build(); 19 | 20 | var networkerSettings = config.GetSection("Networker"); 21 | 22 | var server = new ServerBuilder() 23 | .UseTcp(networkerSettings.GetValue("TcpPort")) 24 | .UseUdp(networkerSettings.GetValue("UdpPort")) 25 | .ConfigureLogging(loggingBuilder => 26 | { 27 | loggingBuilder.AddConfiguration(config.GetSection("Logging")); 28 | loggingBuilder.AddConsole(); 29 | }) 30 | .UseProtobufNet() 31 | .RegisterPacketHandler() 32 | .Build(); 33 | 34 | server.Start(); 35 | 36 | var gameClient = new GameClient(); 37 | gameClient.Client.Connect(); 38 | 39 | while (server.Information.IsRunning) 40 | { 41 | gameClient.Client.Send(new ChatPacket 42 | { 43 | Message = DateTime.Now.ToString() 44 | }); 45 | 46 | Thread.Sleep(10000); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Demos/GameServer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | using Networker.Formatter.ZeroFormatter; 6 | using Networker.Server; 7 | 8 | namespace GameServer 9 | { 10 | internal class Program 11 | { 12 | private static void Main(string[] args) 13 | { 14 | IConfiguration config = new ConfigurationBuilder() 15 | .AddJsonFile("appsettings.json", false, true) 16 | .Build(); 17 | 18 | var serverBuilder = new ServerBuilder() 19 | .UseTcp(1000) 20 | .UseUdp(1001) 21 | .UseConfiguration(config) 22 | .ConfigureLogging(loggingBuilder => 23 | { 24 | loggingBuilder.AddConfiguration(config.GetSection("Logging")); 25 | loggingBuilder.AddConsole(); 26 | }) 27 | .RegisterTypes(serviceCollection => 28 | { 29 | serviceCollection.AddSingleton(); 30 | }) 31 | .RegisterPacketHandler() 32 | .UseZeroFormatter(); 33 | 34 | var server = serverBuilder.Build(); 35 | server.Start(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Networker/Networker.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | https://github.com/MarkioE/Networker 7 | https://github.com/MarkioE/Networker/blob/master/LICENSE 8 | GitHub 9 | https://github.com/MarkioE/Networker 10 | 1.0.0.0 11 | A simple to use TCP and UDP networking library for .NET 12 | 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Networker/Common/Abstractions/IBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Networker.Common.Abstractions 7 | { 8 | public interface IBuilder 9 | { 10 | //Build 11 | TResult Build(); 12 | TBuilder ConfigureLogging(Action loggingBuilder); 13 | 14 | //Service Collection 15 | IServiceCollection GetServiceCollection(); 16 | 17 | IServiceProvider GetServiceProvider(); 18 | 19 | //TBuilder RegisterMiddleware() 20 | // where T : class, IMiddlewareHandler; 21 | 22 | //Packet Handler 23 | TBuilder RegisterPacketHandler() 24 | where TPacket : class where TPacketHandler : IPacketHandler; 25 | 26 | TBuilder RegisterPacketHandlerModule(IPacketHandlerModule packetHandlerModule); 27 | 28 | TBuilder RegisterPacketHandlerModule() 29 | where T : IPacketHandlerModule; 30 | 31 | TBuilder RegisterTypes(Action serviceCollection); 32 | 33 | //Info 34 | TBuilder SetPacketBufferSize(int size); 35 | 36 | TBuilder SetServiceCollection(IServiceCollection serviceCollection, 37 | Func serviceProviderFactory = null); 38 | 39 | TBuilder UseConfiguration(IConfiguration configuration); 40 | 41 | TBuilder UseConfiguration(IConfiguration configuration) 42 | where T : class; 43 | 44 | //Tcp 45 | TBuilder UseTcp(int port); 46 | 47 | //Udp 48 | TBuilder UseUdp(int port); 49 | } 50 | } -------------------------------------------------------------------------------- /Networker/Client/ClientBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common.Abstractions; 4 | using Networker.Server.Abstractions; 5 | 6 | namespace Networker.Client 7 | { 8 | public class ClientBuilder : BuilderBase, IClientBuilder 9 | { 10 | public override IClient Build() 11 | { 12 | SetupSharedDependencies(); 13 | serviceCollection.AddSingleton(); 14 | serviceCollection.AddSingleton(); 15 | serviceCollection.AddSingleton(); 16 | 17 | var serviceProvider = GetServiceProvider(); 18 | return serviceProvider.GetService(); 19 | } 20 | 21 | public T Build() 22 | where T : IClient 23 | { 24 | SetupSharedDependencies(); 25 | serviceCollection.AddSingleton(typeof(T), typeof(Client)); 26 | serviceCollection.AddSingleton(); 27 | serviceCollection.AddSingleton(); 28 | 29 | var serviceProvider = GetServiceProvider(); 30 | return serviceProvider.GetService(); 31 | } 32 | 33 | public IClientBuilder SetPacketBufferPoolSize(int size) 34 | { 35 | options.ObjectPoolSize = size; 36 | return this; 37 | } 38 | 39 | public IClientBuilder UseIp(string ip) 40 | { 41 | if (ip == "localhost") ip = "127.0.0.1"; 42 | 43 | options.Ip = ip; 44 | return this; 45 | } 46 | 47 | public IClientBuilder UseUdp(int port, int localPort) 48 | { 49 | options.UdpPort = port; 50 | options.UdpPortLocal = localPort; 51 | return this; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Networker/Server/TcpConnections.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common; 2 | using Networker.Server.Abstractions; 3 | using System.Collections.Generic; 4 | using System.Net.Sockets; 5 | 6 | namespace Networker.Server 7 | { 8 | public class TcpConnections : ITcpConnections 9 | { 10 | private readonly List connections; 11 | private readonly ObjectPool objectPool; 12 | 13 | public TcpConnections(ServerBuilderOptions options) 14 | { 15 | this.objectPool = new ObjectPool(options.TcpMaxConnections); 16 | 17 | for (var i = 0; i < this.objectPool.Capacity; i++) 18 | { 19 | this.objectPool.Push(new TcpConnection(null)); 20 | } 21 | 22 | this.connections = new List(); 23 | } 24 | 25 | public ITcpConnection Add(Socket socket) 26 | { 27 | var connection = this.objectPool.Pop(); 28 | connection.Socket = socket; 29 | 30 | lock (this.connections) 31 | { 32 | this.connections.Add(connection); 33 | } 34 | 35 | return connection; 36 | } 37 | 38 | public List GetConnections() 39 | { 40 | lock (this.connections) 41 | { 42 | return this.connections; 43 | } 44 | } 45 | 46 | public void Remove(ITcpConnection connection) 47 | { 48 | lock (this.connections) 49 | { 50 | this.connections.Remove(connection); 51 | } 52 | 53 | connection.Socket = null; 54 | this.objectPool.Push(connection); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.MessagePack/MessagePackPacketSerialiser.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | using Networker.Common.Abstractions; 3 | using System; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace Networker.Extensions.MessagePack 8 | { 9 | public class MessagePackPacketSerialiser : IPacketSerialiser 10 | { 11 | public bool CanReadLength => true; 12 | public bool CanReadName => true; 13 | 14 | public bool CanReadOffset => false; 15 | 16 | public T Deserialise(byte[] packetBytes) 17 | { 18 | return MessagePackSerializer.Deserialize(packetBytes); 19 | } 20 | 21 | public T Deserialise(byte[] packetBytes, int offset, int length) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | public byte[] Package(string name, byte[] bytes) 27 | { 28 | using (var memoryStream = new MemoryStream()) 29 | { 30 | using (var binaryWriter = new BinaryWriter(memoryStream)) 31 | { 32 | var nameBytes = Encoding.ASCII.GetBytes(name); 33 | binaryWriter.Write(nameBytes.Length); 34 | binaryWriter.Write(bytes.Length); 35 | binaryWriter.Write(nameBytes); 36 | binaryWriter.Write(bytes); 37 | } 38 | 39 | var packetBytes = memoryStream.ToArray(); 40 | return packetBytes; 41 | } 42 | } 43 | 44 | public byte[] Serialise(T packet) 45 | { 46 | using (var memoryStream = new MemoryStream()) 47 | { 48 | using (var binaryWriter = new BinaryWriter(memoryStream)) 49 | { 50 | var nameBytes = Encoding.ASCII.GetBytes(typeof(T).Name); 51 | var serialised = MessagePackSerializer.Serialize(packet); 52 | binaryWriter.Write(nameBytes.Length); 53 | binaryWriter.Write(serialised.Length); 54 | binaryWriter.Write(nameBytes); 55 | binaryWriter.Write(serialised); 56 | } 57 | 58 | var packetBytes = memoryStream.ToArray(); 59 | return packetBytes; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ZeroFormatter/ZeroFormatterPacketSerialiser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using Networker.Common.Abstractions; 5 | using ZeroFormatter; 6 | 7 | namespace Networker.Extensions.ZeroFormatter 8 | { 9 | public class ZeroFormatterPacketSerialiser : IPacketSerialiser 10 | { 11 | public bool CanReadLength => true; 12 | public bool CanReadName => true; 13 | 14 | public bool CanReadOffset => false; 15 | 16 | public T Deserialise(byte[] packetBytes) 17 | { 18 | return ZeroFormatterSerializer.Deserialize(packetBytes); 19 | } 20 | 21 | public T Deserialise(byte[] packetBytes, int offset, int length) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | public byte[] Package(string name, byte[] bytes) 27 | { 28 | using (var memoryStream = new MemoryStream()) 29 | { 30 | using (var binaryWriter = new BinaryWriter(memoryStream)) 31 | { 32 | var nameBytes = Encoding.ASCII.GetBytes(name); 33 | binaryWriter.Write(nameBytes.Length); 34 | binaryWriter.Write(bytes.Length); 35 | binaryWriter.Write(nameBytes); 36 | binaryWriter.Write(bytes); 37 | } 38 | 39 | var packetBytes = memoryStream.ToArray(); 40 | return packetBytes; 41 | } 42 | } 43 | 44 | public byte[] Serialise(T packet) 45 | { 46 | using (var memoryStream = new MemoryStream()) 47 | { 48 | using (var binaryWriter = new BinaryWriter(memoryStream)) 49 | { 50 | var nameBytes = Encoding.ASCII.GetBytes(typeof(T).Name); 51 | var serialised = ZeroFormatterSerializer.Serialize(packet); 52 | binaryWriter.Write(nameBytes.Length); 53 | binaryWriter.Write(serialised.Length); 54 | binaryWriter.Write(nameBytes); 55 | binaryWriter.Write(serialised); 56 | } 57 | 58 | var packetBytes = memoryStream.ToArray(); 59 | return packetBytes; 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Networker/Server/UdpClientListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Logging; 5 | using Networker.Common; 6 | using Networker.Server.Abstractions; 7 | 8 | namespace Networker.Server 9 | { 10 | public class UdpClientListener : IUdpSocketListener 11 | { 12 | private readonly ObjectPool endPointPool; 13 | private readonly ILogger logger; 14 | private readonly ServerBuilderOptions options; 15 | private readonly IServerInformation serverInformation; 16 | private readonly IServerPacketProcessor serverPacketProcessor; 17 | private UdpClient client; 18 | private IPEndPoint endPoint; 19 | 20 | public UdpClientListener(ServerBuilderOptions options, 21 | ILogger logger, 22 | IServerPacketProcessor serverPacketProcessor, 23 | IServerInformation serverInformation) 24 | { 25 | this.options = options; 26 | this.logger = logger; 27 | this.serverPacketProcessor = serverPacketProcessor; 28 | this.serverInformation = serverInformation; 29 | 30 | endPointPool = new ObjectPool(this.options.UdpSocketObjectPoolSize); 31 | 32 | for (var i = 0; i < endPointPool.Capacity; i++) 33 | endPointPool.Push(new IPEndPoint(IPAddress.Loopback, this.options.UdpPort)); 34 | } 35 | 36 | public IPEndPoint GetEndPoint() 37 | { 38 | return endPoint; 39 | } 40 | 41 | public Socket GetSocket() 42 | { 43 | return client.Client; 44 | } 45 | 46 | public void Listen() 47 | { 48 | client = new UdpClient(); 49 | client.ExclusiveAddressUse = false; 50 | client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 51 | endPoint = new IPEndPoint(IPAddress.Loopback, options.UdpPort); 52 | client.Client.Bind(endPoint); 53 | 54 | logger.LogInformation($"Starting UDP listener on port {options.UdpPort}."); 55 | 56 | Task.Factory.StartNew(() => 57 | { 58 | while (serverInformation.IsRunning) 59 | { 60 | var endpoint = endPointPool.Pop() as IPEndPoint; 61 | 62 | var receivedResults = client.Receive(ref endpoint); 63 | 64 | Process(endpoint, receivedResults); 65 | } 66 | }); 67 | } 68 | 69 | private async Task Process(EndPoint endPoint, byte[] buffer) 70 | { 71 | serverPacketProcessor.ProcessUdpFromBuffer(endPoint, buffer); 72 | 73 | endPointPool.Push(endPoint); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /Extensions/Networker.Extensions.ProtobufNet/ProtoBufNetSerialiser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using Networker.Common; 5 | using Networker.Common.Abstractions; 6 | using ProtoBuf; 7 | 8 | namespace Networker.Extensions.ProtobufNet 9 | { 10 | public class ProtoBufNetSerialiser : IPacketSerialiser 11 | { 12 | private readonly ObjectPool memoryStreamObjectPool; 13 | 14 | public ProtoBufNetSerialiser() 15 | { 16 | memoryStreamObjectPool = new ObjectPool(1500); 17 | 18 | for (var i = 0; i < memoryStreamObjectPool.Capacity; i++) memoryStreamObjectPool.Push(new MemoryStream()); 19 | } 20 | 21 | public bool CanReadLength => true; 22 | public bool CanReadName => true; 23 | 24 | public bool CanReadOffset => false; //Was TRUE 25 | 26 | public T Deserialise(byte[] packetBytes) 27 | { 28 | /*var memoryStream = memoryStreamObjectPool.Pop(); 29 | 30 | memoryStream.SetLength(0); 31 | memoryStream.Write(packetBytes, 0, packetBytes.Length); 32 | 33 | var deserialised = Serializer.Deserialize(memoryStream); 34 | 35 | memoryStreamObjectPool.Push(memoryStream);*/ 36 | //todo: FIX for perf 37 | 38 | return Serializer.Deserialize(new MemoryStream(packetBytes)); 39 | } 40 | 41 | public T Deserialise(byte[] packetBytes, int offset, int length) 42 | { 43 | throw new NotSupportedException(); 44 | } 45 | 46 | public byte[] Package(string name, byte[] bytes) 47 | { 48 | return new byte[] { }; 49 | } 50 | 51 | public byte[] Serialise(T packet) 52 | { 53 | var memoryStream = memoryStreamObjectPool.Pop(); 54 | 55 | memoryStream.SetLength(0); 56 | 57 | Serializer.Serialize(memoryStream, packet); 58 | 59 | var packetBytes = memoryStream.ToArray(); 60 | 61 | var name = typeof(T).Name; 62 | var nameBytes = Encoding.ASCII.GetBytes(name); 63 | 64 | var packetWithData = new byte[packetBytes.Length + 8 + nameBytes.Length]; 65 | 66 | var packetCountBytes = BitConverter.GetBytes(packetBytes.Length); 67 | var packetNameCountBytes = BitConverter.GetBytes(nameBytes.Length); 68 | 69 | var currentPosition = 0; 70 | 71 | foreach (var nameByte in packetNameCountBytes) packetWithData[currentPosition++] = nameByte; 72 | 73 | foreach (var packetByte in packetCountBytes) packetWithData[currentPosition++] = packetByte; 74 | 75 | Buffer.BlockCopy(nameBytes, 0, packetWithData, currentPosition, nameBytes.Length); 76 | 77 | currentPosition += nameBytes.Length; 78 | 79 | Buffer.BlockCopy(packetBytes, 0, packetWithData, currentPosition, packetBytes.Length); 80 | 81 | memoryStreamObjectPool.Push(memoryStream); 82 | 83 | var testDeserialise = Serializer.Deserialize(new MemoryStream(packetBytes)); 84 | return packetWithData; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Networker/Server/UdpSocketListener.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | using Microsoft.Extensions.Logging; 4 | using Networker.Common; 5 | using Networker.Server.Abstractions; 6 | 7 | namespace Networker.Server 8 | { 9 | public class UdpSocketListener : IUdpSocketListener 10 | { 11 | private readonly IBufferManager bufferManager; 12 | private readonly ILogger logger; 13 | private readonly ServerBuilderOptions options; 14 | private readonly IServerPacketProcessor serverPacketProcessor; 15 | private readonly ObjectPool socketEventArgsPool; 16 | private IPEndPoint endPoint; 17 | private Socket listener; 18 | 19 | public UdpSocketListener(ServerBuilderOptions options, 20 | ILogger logger, 21 | IServerPacketProcessor serverPacketProcessor, 22 | IBufferManager bufferManager) 23 | { 24 | this.options = options; 25 | this.logger = logger; 26 | this.serverPacketProcessor = serverPacketProcessor; 27 | this.bufferManager = bufferManager; 28 | socketEventArgsPool = new ObjectPool(options.UdpSocketObjectPoolSize); 29 | } 30 | 31 | public IPEndPoint GetEndPoint() 32 | { 33 | return endPoint; 34 | } 35 | 36 | public Socket GetSocket() 37 | { 38 | return listener; 39 | } 40 | 41 | public void Listen() 42 | { 43 | listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 44 | 45 | endPoint = new IPEndPoint(IPAddress.Loopback, options.UdpPort); 46 | listener.Bind(endPoint); 47 | 48 | for (var i = 0; i < options.UdpSocketObjectPoolSize; i++) 49 | { 50 | var socketEventArgs = new SocketAsyncEventArgs(); 51 | socketEventArgs.Completed += ProcessReceivedData; 52 | socketEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, options.UdpPort); 53 | 54 | socketEventArgsPool.Push(socketEventArgs); 55 | } 56 | 57 | logger.LogDebug($"Starting UDP listener on port {options.UdpPort}."); 58 | listener.Listen(10000); 59 | Process(); 60 | } 61 | 62 | private void Process() 63 | { 64 | var recieveArgs = socketEventArgsPool.Pop(); 65 | bufferManager.SetBuffer(recieveArgs); 66 | 67 | if (!listener.ReceiveFromAsync(recieveArgs)) ProcessReceivedData(this, recieveArgs); 68 | 69 | StartAccept(recieveArgs); 70 | } 71 | 72 | private void ProcessReceivedData(object sender, SocketAsyncEventArgs e) 73 | { 74 | Process(); 75 | 76 | if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) 77 | { 78 | e.SetBuffer(e.Offset, e.BytesTransferred); 79 | serverPacketProcessor.ProcessUdp(e); 80 | } 81 | 82 | socketEventArgsPool.Push(e); 83 | } 84 | 85 | private void StartAccept(SocketAsyncEventArgs acceptEventArg) 86 | { 87 | var willRaiseEvent = listener.AcceptAsync(acceptEventArg); 88 | 89 | if (!willRaiseEvent) ProcessReceivedData(this, acceptEventArg); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Networker/Server/ServerBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Networker.Common.Abstractions; 3 | using Networker.Server.Abstractions; 4 | using System; 5 | 6 | namespace Networker.Server 7 | { 8 | public class ServerBuilder : BuilderBase, IServerBuilder 9 | { 10 | private Type tcpSocketListenerFactory; 11 | private Type udpSocketListenerFactory; 12 | 13 | public ServerBuilder() : base() 14 | { 15 | 16 | } 17 | 18 | public override IServer Build() 19 | { 20 | this.SetupSharedDependencies(); 21 | 22 | this.serviceCollection.AddSingleton(); 23 | this.serviceCollection.AddSingleton(); 24 | this.serviceCollection.AddSingleton(); 25 | this.serviceCollection.AddSingleton(); 26 | this.serviceCollection.AddSingleton(new BufferManager( 27 | this.options.PacketSizeBuffer * this.options.TcpMaxConnections * 5, 28 | this.options.PacketSizeBuffer)); 29 | this.serviceCollection.AddSingleton(); 30 | 31 | if (this.tcpSocketListenerFactory == null) 32 | this.serviceCollection 33 | .AddSingleton(); 34 | 35 | if (this.udpSocketListenerFactory == null) 36 | { 37 | this.serviceCollection 38 | .AddSingleton(); 39 | } 40 | 41 | this.serviceCollection.AddSingleton(collection => collection.GetService().Create()); 42 | 43 | 44 | var serviceProvider = this.GetServiceProvider(); 45 | 46 | 47 | serviceProvider.GetService().SetUdpSender(serviceProvider.GetService()); 48 | return serviceProvider.GetService(); 49 | } 50 | 51 | public IServerBuilder SetMaximumConnections(int maxConnections) 52 | { 53 | this.options.TcpMaxConnections = maxConnections; 54 | return this; 55 | } 56 | 57 | public IServerBuilder UseTcpSocketListener() 58 | where T : class, ITcpSocketListenerFactory 59 | { 60 | this.tcpSocketListenerFactory = typeof(T); 61 | this.serviceCollection.AddSingleton(); 62 | return this; 63 | } 64 | 65 | public IServerBuilder UseUdpSocketListener() 66 | where T : class, IUdpSocketListenerFactory 67 | { 68 | this.udpSocketListenerFactory = typeof(T); 69 | this.serviceCollection.AddSingleton(); 70 | return this; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/k2yi64f298bgjxra?svg=true)](https://ci.appveyor.com/project/MarkioE/networker) 2 | [![NuGet](https://img.shields.io/nuget/v/networker.svg)](https://www.nuget.org/packages/Networker/) 3 | 4 | # Networker 5 | A simple to use TCP and UDP networking library for .NET, designed to be flexible, scalable and FAST. 6 | 7 | ## Supported Frameworks 8 | * .NET Standard 2.0 9 | * .NET Framework 4.7+ for Unity 10 | 11 | ## Features 12 | * TCP 13 | * UDP 14 | * Socket pooling 15 | * Object pooling 16 | * Process thousands of requests per second 17 | * Dependency Injection using [Micrsoft.Extensions.DependencyInjection.ServiceCollection](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=aspnetcore-2.1) 18 | * Logging using [Microsoft.Extensions.Logging](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging?view=aspnetcore-2.2) 19 | * Works with [Unity Game Engine](https://unity3d.com) (.NET Framework only) 20 | 21 | ## Installation 22 | **NuGet Package Manager** 23 | ``` 24 | Install-Package Networker 25 | ``` 26 | 27 | **You must then install one of the following formatters** 28 | 29 | #### ZeroFormatter 30 | ``` 31 | Install-Package Networker.Extensions.ZeroFormatter 32 | ``` 33 | #### MessagePack 34 | ``` 35 | Install-Package Networker.Extensions.MessagePack 36 | ``` 37 | #### Protobuf-net 38 | ``` 39 | Install-Package Networker.Extensions.ProtoBufNet 40 | ``` 41 | #### JSON (Utf8Json) 42 | ``` 43 | Install-Package Networker.Extensions.Json 44 | ``` 45 | 46 | ## Tutorial - Creating a Basic Unity Multiplayer Game with Networker 47 | [Get started with this tutorial written by the library developer Mark Eastwood](https://markeastwood.net/?p=7) 48 | 49 | ## Example 50 | 51 | Creating a server is easy.. 52 | 53 | ````csharp 54 | var server = new ServerBuilder() 55 | .UseTcp(1000) 56 | .UseUdp(5000) 57 | .RegisterPacketHandlerModule() 58 | .RegisterPacketHandlerModule() 59 | .UseZeroFormatter() 60 | .ConfigureLogging(loggingBuilder => 61 | { 62 | loggingBuilder.AddConsole(); 63 | loggingBuilder.SetMinimumLevel( 64 | LogLevel.Debug); 65 | }) 66 | .Build(); 67 | 68 | server.Start(); 69 | ```` 70 | 71 | You can handle a packet easily using dependency injection, logging and built-in deserialisation. 72 | 73 | ````csharp 74 | public class ChatPacketHandler : PacketHandlerBase 75 | { 76 | private readonly ILogger _logger; 77 | 78 | public ChatPacketHandler(ILogger logger) 79 | { 80 | _logger = logger; 81 | } 82 | 83 | public override async Task Process(ChatPacket packet, IPacketContext packetContext) 84 | { 85 | _logger.LogDebug("I received the chat message: " + packet.Message); 86 | 87 | packetContext.Sender.Send(new ChatPacket 88 | { 89 | Message = "Hey, I got your message!" 90 | }); 91 | } 92 | } 93 | ```` 94 | -------------------------------------------------------------------------------- /Networker/Server/Server.cs: -------------------------------------------------------------------------------- 1 | using Networker.Common.Abstractions; 2 | using Networker.Server.Abstractions; 3 | using System; 4 | using System.Net; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace Networker.Server 9 | { 10 | public class Server : IServer 11 | { 12 | public ITcpSocketListener TcpListener { get; } 13 | public IUdpSocketListener UdpListener { get; } 14 | public IServerInformation Information { get; } 15 | 16 | public EventHandler ClientConnected { get; set; } 17 | public EventHandler ClientDisconnected { get; set; } 18 | public EventHandler ServerInformationUpdated { get; set; } 19 | 20 | private readonly IPacketSerialiser packetSerialiser; 21 | private readonly ServerBuilderOptions options; 22 | private readonly ITcpConnections tcpConnections; 23 | private ServerInformationEventArgs eventArgs; 24 | 25 | public Server(ServerBuilderOptions options, 26 | ITcpConnections tcpConnections, 27 | ITcpSocketListenerFactory tcpSocketListenerFactory, 28 | IUdpSocketListener udpSocketListener, 29 | IBufferManager bufferManager, 30 | IServerInformation serverInformation, 31 | IPacketSerialiser packetSerialiser) 32 | { 33 | this.options = options; 34 | this.tcpConnections = tcpConnections; 35 | Information = serverInformation; 36 | this.packetSerialiser = packetSerialiser; 37 | bufferManager.InitBuffer(); 38 | 39 | if (options.TcpPort > 0) TcpListener = tcpSocketListenerFactory.Create(); 40 | 41 | if (options.UdpPort > 0) UdpListener = udpSocketListener; 42 | 43 | Task.Factory.StartNew(() => 44 | { 45 | while (Information.IsRunning) 46 | { 47 | if (eventArgs == null) eventArgs = new ServerInformationEventArgs(); 48 | 49 | eventArgs.ProcessedTcpPackets = serverInformation.ProcessedTcpPackets; 50 | eventArgs.InvalidTcpPackets = serverInformation.InvalidTcpPackets; 51 | eventArgs.ProcessedUdpPackets = serverInformation.ProcessedUdpPackets; 52 | eventArgs.InvalidUdpPackets = serverInformation.InvalidUdpPackets; 53 | eventArgs.TcpConnections = tcpConnections.GetConnections().Count; 54 | 55 | ServerInformationUpdated?.Invoke(this, eventArgs); 56 | 57 | Information.ProcessedTcpPackets = 0; 58 | Information.InvalidTcpPackets = 0; 59 | Information.ProcessedUdpPackets = 0; 60 | Information.InvalidUdpPackets = 0; 61 | 62 | Thread.Sleep(10000); 63 | } 64 | }); 65 | } 66 | 67 | public void Broadcast(T packet) => Broadcast(packetSerialiser.Serialise(packet)); 68 | public void Broadcast(byte[] packet) 69 | { 70 | if (UdpListener == null) throw new Exception("UDP is not enabled"); 71 | 72 | var socket = UdpListener.GetSocket(); 73 | socket.EnableBroadcast = true; 74 | socket.SendTo(packet, new IPEndPoint(IPAddress.Broadcast, this.options.UdpPort)); 75 | } 76 | 77 | public ITcpConnections GetConnections() 78 | { 79 | return tcpConnections; 80 | } 81 | 82 | public void Start() 83 | { 84 | Information.IsRunning = true; 85 | 86 | TcpListener?.Listen(); 87 | UdpListener?.Listen(); 88 | 89 | if (TcpListener != null) 90 | { 91 | TcpListener.ClientConnected += ClientConnectedEvent; 92 | TcpListener.ClientDisconnected += ClientDisconnectedEvent; 93 | } 94 | } 95 | 96 | public void Stop() 97 | { 98 | Information.IsRunning = false; 99 | 100 | if (TcpListener != null) 101 | { 102 | TcpListener.ClientConnected -= ClientConnectedEvent; 103 | TcpListener.ClientDisconnected -= ClientDisconnectedEvent; 104 | } 105 | } 106 | 107 | private void ClientConnectedEvent(object sender, TcpConnectionConnectedEventArgs e) 108 | { 109 | ClientConnected?.Invoke(this, e); 110 | } 111 | 112 | private void ClientDisconnectedEvent(object sender, TcpConnectionDisconnectedEventArgs e) 113 | { 114 | ClientDisconnected?.Invoke(this, e); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /Networker/Common/Abstractions/BuilderBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace Networker.Common.Abstractions 8 | { 9 | public abstract class BuilderBase : IBuilder 10 | where TBuilder : class, IBuilder where TBuilderOptions : class, IBuilderOptions 11 | { 12 | private IConfiguration configuration; 13 | 14 | private Action loggingBuilder; 15 | 16 | //Modules 17 | protected PacketHandlerModule module; 18 | protected List modules; 19 | 20 | //Builder Options 21 | protected TBuilderOptions options; 22 | 23 | //Service Collection 24 | protected IServiceCollection serviceCollection; 25 | private Action serviceCollectionFactory; 26 | protected Func serviceProviderFactory; 27 | 28 | public BuilderBase() 29 | { 30 | options = Activator.CreateInstance(); 31 | serviceCollection = new ServiceCollection(); 32 | modules = new List(); 33 | module = new PacketHandlerModule(); 34 | modules.Add(module); 35 | } 36 | 37 | public abstract TResult Build(); 38 | 39 | public TBuilder ConfigureLogging(Action loggingBuilder) 40 | { 41 | this.loggingBuilder = loggingBuilder; 42 | return this as TBuilder; 43 | } 44 | 45 | public IServiceCollection GetServiceCollection() 46 | { 47 | return serviceCollection; 48 | } 49 | 50 | public IServiceProvider GetServiceProvider() 51 | { 52 | var serviceProvider = serviceProviderFactory != null 53 | ? serviceProviderFactory.Invoke() 54 | : serviceCollection.BuildServiceProvider(); 55 | try 56 | { 57 | PacketSerialiserProvider.PacketSerialiser = serviceProvider.GetService(); 58 | } 59 | catch (Exception ex) 60 | { 61 | throw new Exception("No packet serialiser has been configured for Networker"); 62 | } 63 | 64 | if (PacketSerialiserProvider.PacketSerialiser == null) 65 | throw new Exception("No packet serialiser has been configured for Networker"); 66 | 67 | var packetHandlers = serviceProvider.GetService(); 68 | foreach (var packetHandlerModule in modules) 69 | foreach (var packetHandler in packetHandlerModule.GetPacketHandlers()) 70 | packetHandlers.Add( 71 | PacketSerialiserProvider.PacketSerialiser.CanReadName ? packetHandler.Key.Name : "Default", 72 | (IPacketHandler) serviceProvider.GetService(packetHandler.Value)); 73 | 74 | if (!PacketSerialiserProvider.PacketSerialiser.CanReadName && packetHandlers.GetPacketHandlers() 75 | .Count > 1) 76 | throw new Exception( 77 | "A PacketSerialiser which cannot identify a packet can only support up to one packet type"); 78 | 79 | return serviceProvider; 80 | } 81 | 82 | //public TBuilder RegisterMiddleware() 83 | // where T : class, IMiddlewareHandler 84 | //{ 85 | // serviceCollection.AddSingleton(); 86 | // return this as TBuilder; 87 | //} 88 | 89 | public TBuilder RegisterPacketHandler() 90 | where TPacket : class where TPacketHandler : IPacketHandler 91 | { 92 | module.AddPacketHandler(); 93 | return this as TBuilder; 94 | } 95 | 96 | public TBuilder RegisterPacketHandlerModule(IPacketHandlerModule packetHandlerModule) 97 | { 98 | modules.Add(packetHandlerModule); 99 | return this as TBuilder; 100 | } 101 | 102 | public TBuilder RegisterPacketHandlerModule() 103 | where T : IPacketHandlerModule 104 | { 105 | modules.Add(Activator.CreateInstance()); 106 | return this as TBuilder; 107 | } 108 | 109 | public TBuilder RegisterTypes(Action serviceCollection) 110 | { 111 | serviceCollectionFactory = serviceCollection; 112 | return this as TBuilder; 113 | } 114 | 115 | public TBuilder SetPacketBufferSize(int size) 116 | { 117 | options.PacketSizeBuffer = size; 118 | return this as TBuilder; 119 | } 120 | 121 | public TBuilder SetServiceCollection(IServiceCollection serviceCollection, 122 | Func serviceProviderFactory = null) 123 | { 124 | this.serviceCollection = serviceCollection; 125 | this.serviceProviderFactory = serviceProviderFactory; 126 | return this as TBuilder; 127 | } 128 | 129 | public TBuilder UseConfiguration(IConfiguration configuration) 130 | { 131 | this.configuration = configuration; 132 | serviceCollection.AddSingleton(configuration); 133 | return this as TBuilder; 134 | } 135 | 136 | public TBuilder UseConfiguration(IConfiguration configuration) 137 | where T : class 138 | { 139 | this.configuration = configuration; 140 | serviceCollection.AddSingleton(configuration); 141 | serviceCollection.Configure(configuration); 142 | return this as TBuilder; 143 | } 144 | 145 | public TBuilder UseTcp(int port) 146 | { 147 | options.TcpPort = port; 148 | return this as TBuilder; 149 | } 150 | 151 | public TBuilder UseUdp(int port) 152 | { 153 | options.UdpPort = port; 154 | return this as TBuilder; 155 | } 156 | 157 | protected void SetupSharedDependencies() 158 | { 159 | foreach (var packetHandlerModule in modules) 160 | foreach (var packetHandler in packetHandlerModule.GetPacketHandlers()) 161 | serviceCollection.AddSingleton(packetHandler.Value); 162 | 163 | serviceCollection.AddSingleton(options); 164 | serviceCollection.AddSingleton(); 165 | 166 | if (loggingBuilder == null) loggingBuilder = loggerBuilderFactory => { }; 167 | 168 | serviceCollection.AddLogging(loggingBuilder); 169 | serviceCollectionFactory?.Invoke(serviceCollection); 170 | } 171 | } 172 | } -------------------------------------------------------------------------------- /Networker/Client/Client.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common; 4 | using Networker.Common.Abstractions; 5 | using System; 6 | using System.Net; 7 | using System.Net.NetworkInformation; 8 | using System.Net.Sockets; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Networker.Client 13 | { 14 | public class Client : IClient 15 | { 16 | private readonly ILogger logger; 17 | private readonly ClientBuilderOptions options; 18 | private readonly IClientPacketProcessor packetProcessor; 19 | private readonly IPacketSerialiser packetSerialiser; 20 | private readonly byte[] pingPacketBuffer; 21 | private readonly PingOptions pingOptions; 22 | 23 | private bool isRunning = true; 24 | private Socket tcpSocket; 25 | private UdpClient udpClient; 26 | private IPEndPoint udpEndpoint; 27 | 28 | public EventHandler Connected { get; set; } 29 | public EventHandler Disconnected { get; set; } 30 | 31 | public Client(ClientBuilderOptions options, 32 | IPacketSerialiser packetSerialiser, 33 | IClientPacketProcessor packetProcessor, 34 | ILogger logger) 35 | { 36 | this.options = options; 37 | this.packetSerialiser = packetSerialiser; 38 | this.packetProcessor = packetProcessor; 39 | this.logger = logger; 40 | this.pingPacketBuffer = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaa"); 41 | this.pingOptions = new PingOptions(64, true); 42 | } 43 | 44 | /// 45 | public ConnectResult Connect() 46 | { 47 | if (this.options.TcpPort > 0 && this.tcpSocket == null) 48 | { 49 | try 50 | { 51 | this.tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 52 | this.tcpSocket.Connect(this.options.Ip, this.options.TcpPort); 53 | } 54 | catch (Exception exception) 55 | { 56 | return new ConnectResult(exception.Message); 57 | } 58 | 59 | this.Connected?.Invoke(this, this.tcpSocket); 60 | 61 | StartTcpSocketThread(); 62 | } 63 | 64 | if (this.options.UdpPort > 0 && this.udpClient == null) 65 | { 66 | try 67 | { 68 | var address = IPAddress.Parse(this.options.Ip); 69 | this.udpClient = new UdpClient(this.options.UdpPortLocal); 70 | this.udpEndpoint = new IPEndPoint(address, this.options.UdpPort); 71 | } 72 | catch (Exception exception) 73 | { 74 | return new ConnectResult(exception.Message); 75 | } 76 | 77 | StartUdpSocketThread(); 78 | } 79 | 80 | return new ConnectResult(true); 81 | } 82 | 83 | /// 84 | public long Ping(int timeout) 85 | { 86 | var pingSender = new Ping(); 87 | var reply = pingSender.Send(this.options.Ip, timeout, this.pingPacketBuffer, this.pingOptions); 88 | 89 | if (reply.Status == IPStatus.Success) 90 | { 91 | return reply.RoundtripTime; 92 | } 93 | 94 | this.logger.LogError($"Could not get ping {reply.Status}"); 95 | return -1; 96 | } 97 | 98 | /// 99 | public void Send(T packet) => Send(this.packetSerialiser.Serialise(packet)); 100 | 101 | /// 102 | public void Send(byte[] packet) 103 | { 104 | if (this.tcpSocket == null) 105 | { 106 | throw new Exception("TCP client has not been initialised. Have you called .Connect()?"); 107 | } 108 | 109 | this.tcpSocket.Send(packet); 110 | } 111 | 112 | /// 113 | public void SendUdp(T packet) => SendUdp(this.packetSerialiser.Serialise(packet)); 114 | 115 | /// 116 | public void SendUdp(byte[] packet) 117 | { 118 | if (this.udpClient == null) 119 | { 120 | throw new Exception("UDP client has not been initialised. Have you called .Connect()?"); 121 | } 122 | 123 | this.udpClient.Send(packet, packet.Length, this.udpEndpoint); 124 | } 125 | 126 | /// 127 | public void Stop() 128 | { 129 | this.isRunning = false; 130 | } 131 | 132 | private void StartTcpSocketThread() 133 | { 134 | Task.Factory.StartNew(() => 135 | { 136 | while (this.isRunning) 137 | { 138 | if (this.tcpSocket.Poll(10, SelectMode.SelectWrite)) 139 | { 140 | this.packetProcessor.Process(this.tcpSocket); 141 | } 142 | 143 | if (!this.tcpSocket.Connected) 144 | { 145 | this.Disconnected?.Invoke(this, this.tcpSocket); 146 | break; 147 | } 148 | } 149 | 150 | if (this.tcpSocket.Connected) 151 | { 152 | this.tcpSocket.Disconnect(false); 153 | this.tcpSocket.Close(); 154 | this.Disconnected?.Invoke(this, this.tcpSocket); 155 | } 156 | 157 | this.tcpSocket = null; 158 | }); 159 | } 160 | 161 | private void StartUdpSocketThread() 162 | { 163 | Task.Factory.StartNew(() => 164 | { 165 | this.logger.LogInformation( 166 | $"Connecting to UDP at {this.options.Ip}:{this.options.UdpPort}"); 167 | 168 | while (this.isRunning) 169 | { 170 | try 171 | { 172 | var data = this.udpClient.ReceiveAsync() 173 | .GetAwaiter() 174 | .GetResult(); 175 | 176 | this.packetProcessor.Process(data); 177 | } 178 | catch (Exception ex) 179 | { 180 | this.logger.Error(ex); 181 | } 182 | } 183 | 184 | this.udpClient = null; 185 | }); 186 | } 187 | } 188 | } -------------------------------------------------------------------------------- /Networker/Client/ClientPacketProcessor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Client.Abstractions; 3 | using Networker.Common; 4 | using Networker.Common.Abstractions; 5 | using Networker.Server.Abstractions; 6 | using System; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | 10 | namespace Networker.Client 11 | { 12 | public class ClientPacketProcessor : IClientPacketProcessor 13 | { 14 | private readonly ObjectPool bytePool; 15 | private readonly ILogger logger; 16 | private readonly ClientBuilderOptions options; 17 | private readonly IPacketHandlers packetHandlers; 18 | private readonly IPacketSerialiser packetSerialiser; 19 | private readonly ObjectPool tcpSenderObjectPool; 20 | private readonly ObjectPool udpSenderObjectPool; 21 | 22 | private IUdpSocketSender _udpSocketSender; 23 | private ObjectPool _packetContextObjectPool; 24 | 25 | public ClientPacketProcessor(ClientBuilderOptions options, 26 | IPacketSerialiser packetSerialiser, 27 | ILogger logger, 28 | IPacketHandlers packetHandlers) 29 | { 30 | this.options = options; 31 | this.packetSerialiser = packetSerialiser; 32 | this.logger = logger; 33 | this.packetHandlers = packetHandlers; 34 | 35 | tcpSenderObjectPool = new ObjectPool(options.ObjectPoolSize); 36 | 37 | for (var i = 0; i < tcpSenderObjectPool.Capacity; i++) 38 | tcpSenderObjectPool.Push(new TcpSender(packetSerialiser)); 39 | 40 | udpSenderObjectPool = new ObjectPool(options.ObjectPoolSize); 41 | 42 | for (var i = 0; i < udpSenderObjectPool.Capacity; i++) 43 | udpSenderObjectPool.Push(new UdpSender(_udpSocketSender)); 44 | 45 | _packetContextObjectPool = new ObjectPool(options.ObjectPoolSize * 2); 46 | 47 | for (var i = 0; i < _packetContextObjectPool.Capacity; i++) 48 | _packetContextObjectPool.Push(new PacketContext() 49 | { 50 | Serialiser = this.packetSerialiser 51 | }); 52 | 53 | bytePool = new ObjectPool(options.ObjectPoolSize); 54 | 55 | for (var i = 0; i < bytePool.Capacity; i++) bytePool.Push(new byte[options.PacketSizeBuffer]); 56 | } 57 | 58 | public void Process(Socket socket) 59 | { 60 | var buffer = bytePool.Pop(); 61 | var sender = tcpSenderObjectPool.Pop(); 62 | 63 | try 64 | { 65 | socket.Receive(buffer); 66 | 67 | var tcpSender = sender as TcpSender; 68 | tcpSender.Socket = socket; 69 | 70 | Process(buffer, sender); 71 | } 72 | catch (Exception ex) 73 | { 74 | logger.Error(ex); 75 | } 76 | finally 77 | { 78 | bytePool.Push(buffer); 79 | tcpSenderObjectPool.Push(sender); 80 | } 81 | } 82 | 83 | public void Process(UdpReceiveResult data) 84 | { 85 | var sender = udpSenderObjectPool.Pop(); 86 | 87 | try 88 | { 89 | var buffer = data.Buffer; 90 | 91 | var udpSender = sender as UdpSender; 92 | udpSender.RemoteEndpoint = data.RemoteEndPoint; 93 | 94 | Process(buffer, sender); 95 | } 96 | catch (Exception ex) 97 | { 98 | logger.Error(ex); 99 | } 100 | finally 101 | { 102 | udpSenderObjectPool.Push(sender); 103 | } 104 | } 105 | 106 | public void SetUdpSocketSender(IUdpSocketSender socketSender) 107 | { 108 | _udpSocketSender = socketSender; 109 | } 110 | 111 | private void Process(byte[] buffer, ISender sender) 112 | { 113 | var bytesRead = 0; 114 | var currentPosition = 0; 115 | 116 | while (bytesRead < buffer.Length) 117 | { 118 | var packetTypeNameLength = packetSerialiser.CanReadName 119 | ? BitConverter.ToInt32(buffer, currentPosition) 120 | : 0; 121 | 122 | if (packetSerialiser.CanReadName) currentPosition += 4; 123 | 124 | var packetSize = packetSerialiser.CanReadLength 125 | ? BitConverter.ToInt32(buffer, currentPosition) 126 | : 0; 127 | 128 | if (packetSerialiser.CanReadLength) currentPosition += 4; 129 | 130 | var packetTypeName = "Default"; 131 | 132 | if (packetSerialiser.CanReadName) 133 | { 134 | if (buffer.Length - currentPosition < packetTypeNameLength) 135 | { 136 | return; 137 | } 138 | 139 | packetTypeName = Encoding.ASCII.GetString(buffer, currentPosition, packetTypeNameLength); 140 | currentPosition += packetTypeNameLength; 141 | 142 | if (string.IsNullOrEmpty(packetTypeName)) 143 | { 144 | //logger.Error(new Exception("Packet was lost - Invalid")); 145 | return; 146 | } 147 | } 148 | 149 | var packetHandler = packetHandlers.GetPacketHandlers()[packetTypeName]; 150 | 151 | if (packetSerialiser.CanReadLength && buffer.Length - bytesRead < packetSize) 152 | { 153 | logger.Error(new Exception("Packet was lost")); 154 | return; 155 | } 156 | 157 | var context = _packetContextObjectPool.Pop(); 158 | context.Sender = sender; 159 | 160 | if (packetSerialiser.CanReadOffset) 161 | { 162 | context.PacketBytes = buffer; 163 | //packetHandler.Handle(buffer, currentPosition, packetSize, context).GetAwaiter().GetResult(); 164 | //Not required/supported right now 165 | } 166 | else 167 | { 168 | var packetBytes = new byte[packetSize]; 169 | Buffer.BlockCopy(buffer, currentPosition, packetBytes, 0, packetSize); 170 | context.PacketBytes = packetBytes; 171 | packetHandler.Handle(context).GetAwaiter().GetResult(); 172 | } 173 | 174 | _packetContextObjectPool.Push(context); 175 | 176 | currentPosition += packetSize; 177 | bytesRead += packetSize + packetTypeNameLength; 178 | 179 | if (packetSerialiser.CanReadName) bytesRead += 4; 180 | if (packetSerialiser.CanReadLength) bytesRead += 4; 181 | } 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /Networker/Server/ServerPacketProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Sockets; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Microsoft.Extensions.Logging; 9 | using Networker.Common; 10 | using Networker.Common.Abstractions; 11 | using Networker.Server.Abstractions; 12 | 13 | namespace Networker.Server 14 | { 15 | public class ServerPacketProcessor : IServerPacketProcessor 16 | { 17 | private readonly ILogger logger; 18 | private readonly List middlewares; 19 | private readonly ObjectPool packetContextObjectPool; 20 | private readonly IPacketHandlers packetHandlers; 21 | private readonly IPacketSerialiser packetSerialiser; 22 | private readonly IServerInformation serverInformation; 23 | private readonly ObjectPool tcpSenderObjectPool; 24 | private readonly ObjectPool udpSenderObjectPool; 25 | private IUdpSocketSender _socketSender; 26 | 27 | public ServerPacketProcessor(ServerBuilderOptions options, 28 | ILogger logger, 29 | IPacketHandlers packetHandlers, 30 | IServerInformation serverInformation, 31 | IPacketSerialiser packetSerialiser, 32 | IEnumerable middlewares) 33 | { 34 | this.logger = logger; 35 | this.packetHandlers = packetHandlers; 36 | this.serverInformation = serverInformation; 37 | this.packetSerialiser = packetSerialiser; 38 | this.middlewares = middlewares.ToList(); 39 | 40 | tcpSenderObjectPool = new ObjectPool(options.TcpMaxConnections); 41 | 42 | for (var i = 0; i < tcpSenderObjectPool.Capacity; i++) 43 | tcpSenderObjectPool.Push(new TcpSender(packetSerialiser)); 44 | 45 | udpSenderObjectPool = new ObjectPool(options.TcpMaxConnections * 2); 46 | 47 | for (var i = 0; i < udpSenderObjectPool.Capacity; i++) 48 | udpSenderObjectPool.Push(new UdpSender(_socketSender)); 49 | 50 | packetContextObjectPool = new ObjectPool(options.TcpMaxConnections * 2); 51 | 52 | for (var i = 0; i < packetContextObjectPool.Capacity; i++) 53 | packetContextObjectPool.Push(new PacketContext()); 54 | } 55 | 56 | public async Task ProcessFromBuffer(ISender sender, 57 | byte[] buffer, 58 | int offset = 0, 59 | int length = 0, 60 | bool isTcp = true) 61 | { 62 | var bytesRead = 0; 63 | var currentPosition = offset; 64 | 65 | if (length == 0) 66 | length = buffer.Length; 67 | 68 | while (bytesRead < length) 69 | { 70 | var packetNameSize = packetSerialiser.CanReadName 71 | ? BitConverter.ToInt32(buffer, currentPosition) 72 | : 0; 73 | 74 | if (packetSerialiser.CanReadName) currentPosition += 4; 75 | 76 | var packetSize = packetSerialiser.CanReadLength 77 | ? BitConverter.ToInt32(buffer, currentPosition) 78 | : 0; 79 | 80 | if (packetSerialiser.CanReadLength) currentPosition += 4; 81 | 82 | try 83 | { 84 | var packetTypeName = "Default"; 85 | 86 | if (packetSerialiser.CanReadName) 87 | packetTypeName = Encoding.ASCII.GetString(buffer, currentPosition, packetNameSize); 88 | 89 | var packetHandlerDictionary = packetHandlers.GetPacketHandlers(); 90 | 91 | if (!packetHandlerDictionary.ContainsKey(packetTypeName)) 92 | { 93 | logger.LogWarning( 94 | $"Could not handle packet {packetTypeName}. Make sure you have registered a handler"); 95 | return; 96 | } 97 | 98 | var packetHandler = packetHandlerDictionary[packetTypeName]; 99 | 100 | if (string.IsNullOrEmpty(packetTypeName)) 101 | { 102 | if (isTcp) 103 | serverInformation.InvalidTcpPackets++; 104 | else 105 | serverInformation.InvalidUdpPackets++; 106 | 107 | logger.Error(new Exception("Packet was lost - Invalid")); 108 | return; 109 | } 110 | 111 | if (packetSerialiser.CanReadName) currentPosition += packetNameSize; 112 | 113 | var packetContext = packetContextObjectPool.Pop(); 114 | packetContext.PacketName = packetTypeName; 115 | packetContext.Sender = sender; 116 | packetContext.Serialiser = packetSerialiser; 117 | packetContext.Handler = packetHandler; 118 | 119 | if (packetSerialiser.CanReadOffset) 120 | { 121 | //todo: Fix 122 | //packetContext.PacketBytes = buffer; 123 | //packetHandler.Handle(buffer, currentPosition, packetSize, packetContext).GetAwaiter().GetResult(); 124 | } 125 | else 126 | { 127 | packetContext.PacketBytes = new byte[packetSize]; 128 | Buffer.BlockCopy(buffer, currentPosition, packetContext.PacketBytes, 0, packetSize); 129 | } 130 | 131 | await packetHandler.Handle(packetContext); 132 | 133 | packetContextObjectPool.Push(packetContext); 134 | } 135 | catch (Exception e) 136 | { 137 | logger.Error(e); 138 | } 139 | 140 | if (packetSerialiser.CanReadLength) currentPosition += packetSize; 141 | 142 | bytesRead += packetSize + packetNameSize; 143 | 144 | if (packetSerialiser.CanReadName) bytesRead += 4; 145 | 146 | if (packetSerialiser.CanReadLength) bytesRead += 4; 147 | 148 | if (isTcp) 149 | serverInformation.ProcessedTcpPackets++; 150 | else 151 | serverInformation.ProcessedUdpPackets++; 152 | } 153 | } 154 | 155 | public void ProcessTcp(SocketAsyncEventArgs socketEvent) 156 | { 157 | var sender = tcpSenderObjectPool.Pop() as TcpSender; 158 | try 159 | { 160 | sender.Socket = ((AsyncUserToken) socketEvent.UserToken).Socket; 161 | ProcessPacketsFromSocketEventArgs(sender, socketEvent); 162 | } 163 | catch (Exception e) 164 | { 165 | logger.Error(e); 166 | } 167 | 168 | tcpSenderObjectPool.Push(sender); 169 | } 170 | 171 | public void ProcessUdp(SocketAsyncEventArgs socketEvent) 172 | { 173 | var sender = udpSenderObjectPool.Pop() as UdpSender; 174 | try 175 | { 176 | sender.RemoteEndpoint = socketEvent.RemoteEndPoint as IPEndPoint; 177 | ProcessPacketsFromSocketEventArgs(sender, socketEvent, false); 178 | } 179 | catch (Exception e) 180 | { 181 | logger.Error(e); 182 | } 183 | 184 | udpSenderObjectPool.Push(sender); 185 | } 186 | 187 | public void ProcessUdpFromBuffer(EndPoint endPoint, byte[] buffer, int offset = 0, int length = 0) 188 | { 189 | var sender = udpSenderObjectPool.Pop() as UdpSender; 190 | try 191 | { 192 | sender.RemoteEndpoint = endPoint as IPEndPoint; 193 | 194 | ProcessFromBuffer(sender, buffer, offset, length, false) 195 | .GetAwaiter() 196 | .GetResult(); 197 | } 198 | catch (Exception e) 199 | { 200 | logger.Error(e); 201 | } 202 | 203 | udpSenderObjectPool.Push(sender); 204 | } 205 | 206 | public void SetUdpSender(IUdpSocketSender sender) 207 | { 208 | _socketSender = sender; 209 | for (var i = 0; i < udpSenderObjectPool.Capacity; i++) 210 | udpSenderObjectPool.Push(new UdpSender(_socketSender)); 211 | } 212 | 213 | private void ProcessPacketsFromSocketEventArgs(ISender sender, 214 | SocketAsyncEventArgs eventArgs, 215 | bool isTcp = true) 216 | { 217 | ProcessFromBuffer(sender, 218 | eventArgs.Buffer, 219 | eventArgs.Offset, 220 | eventArgs.BytesTransferred, 221 | isTcp) 222 | .GetAwaiter() 223 | .GetResult(); 224 | } 225 | } 226 | } -------------------------------------------------------------------------------- /Networker/Server/TcpSocketListener.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Networker.Common; 3 | using Networker.Server.Abstractions; 4 | using System; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Threading; 9 | 10 | namespace Networker.Server 11 | { 12 | public class TcpSocketListener : ITcpSocketListener 13 | { 14 | private readonly IBufferManager bufferManager; 15 | private readonly ILogger logger; 16 | private readonly ITcpConnections tcpConnections; 17 | readonly Semaphore maxNumberAcceptedClients; 18 | private readonly ServerBuilderOptions serverBuilderOptions; 19 | private readonly IServerPacketProcessor serverPacketProcessor; 20 | private readonly ObjectPool socketEventArgsPool; 21 | private Socket listenSocket; 22 | 23 | public TcpSocketListener(ServerBuilderOptions serverBuilderOptions, 24 | IServerPacketProcessor serverPacketProcessor, 25 | IBufferManager bufferManager, 26 | ILogger logger, 27 | ITcpConnections tcpConnections) 28 | { 29 | this.serverBuilderOptions = serverBuilderOptions; 30 | this.serverPacketProcessor = serverPacketProcessor; 31 | this.bufferManager = bufferManager; 32 | this.logger = logger; 33 | this.tcpConnections = tcpConnections; 34 | this.socketEventArgsPool = 35 | new ObjectPool(serverBuilderOptions.TcpMaxConnections); 36 | this.maxNumberAcceptedClients = new Semaphore(this.serverBuilderOptions.TcpMaxConnections, 37 | this.serverBuilderOptions.TcpMaxConnections); 38 | } 39 | 40 | public EventHandler ClientConnected { get; set; } 41 | public EventHandler ClientDisconnected { get; set; } 42 | 43 | public void EventArgCompleted(object sender, SocketAsyncEventArgs e) 44 | { 45 | this.ProcessAccept(e); 46 | } 47 | 48 | public Socket GetSocket() 49 | { 50 | return this.listenSocket; 51 | } 52 | 53 | public void Listen() 54 | { 55 | this.listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 56 | this.listenSocket.Bind(new IPEndPoint(IPAddress.Any, this.serverBuilderOptions.TcpPort)); 57 | 58 | for (int i = 0; i < this.serverBuilderOptions.TcpMaxConnections; i++) 59 | { 60 | var socketAsyncEventArgs = new SocketAsyncEventArgs(); 61 | socketAsyncEventArgs.Completed += new EventHandler(this.Completed); 62 | socketAsyncEventArgs.UserToken = new AsyncUserToken(); 63 | 64 | this.bufferManager.SetBuffer(socketAsyncEventArgs); 65 | 66 | this.socketEventArgsPool.Push(socketAsyncEventArgs); 67 | } 68 | 69 | this.listenSocket.Listen(this.serverBuilderOptions.TcpMaxConnections); 70 | this.StartAccept(null); 71 | 72 | this.logger.LogInformation($"Started TCP listener on port {this.serverBuilderOptions.TcpPort}."); 73 | } 74 | 75 | private void CloseClientSocket(SocketAsyncEventArgs e) 76 | { 77 | AsyncUserToken token = e.UserToken as AsyncUserToken; 78 | 79 | this.logger.LogInformation( 80 | $"TCP Client Disconnected. IP: {(token.Socket.RemoteEndPoint as IPEndPoint).Address}"); 81 | 82 | var connection = 83 | this.tcpConnections.GetConnections().FirstOrDefault(f => f.Socket == ((AsyncUserToken)e.UserToken).Socket); 84 | 85 | if (connection != null) 86 | { 87 | this.tcpConnections.Remove(connection); 88 | } 89 | 90 | this.ClientDisconnected?.Invoke(this, 91 | new TcpConnectionDisconnectedEventArgs(new TcpConnection(token.Socket))); 92 | 93 | try 94 | { 95 | token.Socket.Shutdown(SocketShutdown.Send); 96 | } 97 | catch (Exception) { } 98 | 99 | this.socketEventArgsPool.Push(e); 100 | } 101 | 102 | private void Completed(object sender, SocketAsyncEventArgs e) 103 | { 104 | switch (e.LastOperation) 105 | { 106 | case SocketAsyncOperation.Receive: 107 | this.ProcessReceive(e); 108 | break; 109 | case SocketAsyncOperation.Send: 110 | this.ProcessSend(e); 111 | break; 112 | default: 113 | throw new ArgumentException( 114 | "The last operation completed on the socket was not a receive or send"); 115 | } 116 | } 117 | 118 | private void ProcessAccept(SocketAsyncEventArgs e) 119 | { 120 | SocketAsyncEventArgs readEventArgs = this.socketEventArgsPool.Pop(); 121 | 122 | ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket; 123 | 124 | var connection = this.tcpConnections.Add(((AsyncUserToken)readEventArgs.UserToken).Socket); 125 | 126 | this.logger.LogDebug( 127 | $"TCP Client Connected. IP: {(connection.Socket.RemoteEndPoint as IPEndPoint).Address}"); 128 | 129 | this.ClientConnected?.Invoke(this, new TcpConnectionConnectedEventArgs(connection)); 130 | 131 | this.maxNumberAcceptedClients.WaitOne(); 132 | bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs); 133 | if (!willRaiseEvent) 134 | { 135 | this.ProcessReceive(readEventArgs); 136 | } 137 | 138 | this.StartAccept(e); 139 | } 140 | 141 | private void ProcessReceive(SocketAsyncEventArgs e) 142 | { 143 | try 144 | { 145 | if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) 146 | { 147 | this.serverPacketProcessor.ProcessTcp(e); 148 | 149 | this.ProcessSend(e); 150 | } 151 | else 152 | { 153 | this.CloseClientSocket(e); 154 | } 155 | } 156 | catch (Exception exception) 157 | { 158 | this.logger.Error(exception); 159 | } 160 | } 161 | 162 | private void ProcessSend(SocketAsyncEventArgs e) 163 | { 164 | if (e.SocketError == SocketError.Success) 165 | { 166 | AsyncUserToken token = (AsyncUserToken)e.UserToken; 167 | 168 | bool willRaiseEvent = token.Socket.ReceiveAsync(e); 169 | if (!willRaiseEvent) 170 | { 171 | this.ProcessReceive(e); 172 | } 173 | } 174 | else 175 | { 176 | this.CloseClientSocket(e); 177 | } 178 | } 179 | 180 | private void StartAccept(SocketAsyncEventArgs acceptEventArg) 181 | { 182 | try 183 | { 184 | if (acceptEventArg == null) 185 | { 186 | acceptEventArg = new SocketAsyncEventArgs(); 187 | acceptEventArg.Completed += 188 | new EventHandler(this.EventArgCompleted); 189 | } 190 | else 191 | { 192 | acceptEventArg.AcceptSocket = null; 193 | } 194 | 195 | bool willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg); 196 | if (!willRaiseEvent) 197 | { 198 | this.ProcessAccept(acceptEventArg); 199 | } 200 | } 201 | catch (Exception e) 202 | { 203 | this.logger.Error(e); 204 | } 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Networker.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2006 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker", "Networker\Networker.csproj", "{9BE176AA-8128-438D-B6AB-3075545DDB9F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B83B1F14-CC19-4B40-B0F3-28B18CB56760}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{84C88291-7FC8-47AC-84FA-9CF5DF39028C}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Basic", "Demos\Demo.Basic\Demo.Basic.csproj", "{8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Common", "Demos\Demo.Common\Demo.Common.csproj", "{50CD08BC-5CB5-471E-A40E-B7EFFC86E853}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Middleware", "Demos\Demo.Middleware\Demo.Middleware.csproj", "{8DF05FEF-FBBB-4FBF-9595-44A270C972C5}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{C2A80735-2797-474C-9879-126B562DD2F5}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Extensions.Json", "Extensions\Networker.Extensions.Json\Networker.Extensions.Json.csproj", "{362A819C-58DD-4F6D-B23E-CEA104D7E78A}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Extensions.ProtobufNet", "Extensions\Networker.Extensions.ProtobufNet\Networker.Extensions.ProtobufNet.csproj", "{658A2DCE-2702-42F7-8C71-CDCA9A05E6B4}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Extensions.ZeroFormatter", "Extensions\Networker.Extensions.ZeroFormatter\Networker.Extensions.ZeroFormatter.csproj", "{4122B5B6-5888-4F9B-AECE-28C98A0BB7A9}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Tests.ZeroFormatter", "Tests\Networker.Tests.ZeroFormatter\Networker.Tests.ZeroFormatter.csproj", "{C6FE3C36-AF81-41E8-88B0-3AAC9C56348F}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Tests.Json", "Tests\Networker.Tests.Json\Networker.Tests.Json.csproj", "{BF2B363F-AB41-4BC8-A149-49EC59F06265}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Networker.Tests.ProtobufNet", "Tests\Networker.Tests.ProtobufNet\Networker.Tests.ProtobufNet.csproj", "{9F66679A-191B-4551-ADBC-65A3430F9356}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tutorial.Server", "Demos\Tutorial.Server\Tutorial.Server.csproj", "{6ADC9B53-4FB7-487A-8D61-CC4981C30269}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tutorial.Client", "Demos\Tutorial.Client\Tutorial.Client.csproj", "{F7226539-2B8F-492F-B9BD-DA81E298AE67}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tutorial.Common", "Demos\Tutorial.Common\Tutorial.Common.csproj", "{D6542750-89CB-4D09-9E7B-EAAA392D4E5D}" 37 | EndProject 38 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networker.Extensions.MessagePack", "Extensions\Networker.Extensions.MessagePack\Networker.Extensions.MessagePack.csproj", "{E41A6B84-9548-48D5-9908-AE2C8517EDC9}" 39 | EndProject 40 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networker.Tests.MessagePack", "Tests\Networker.Tests.MessagePack\Networker.Tests.MessagePack.csproj", "{BC44C424-5E6A-431B-80F9-5C597F50E042}" 41 | EndProject 42 | Global 43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 44 | Debug|Any CPU = Debug|Any CPU 45 | Release|Any CPU = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 48 | {9BE176AA-8128-438D-B6AB-3075545DDB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {9BE176AA-8128-438D-B6AB-3075545DDB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {9BE176AA-8128-438D-B6AB-3075545DDB9F}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {9BE176AA-8128-438D-B6AB-3075545DDB9F}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {50CD08BC-5CB5-471E-A40E-B7EFFC86E853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {50CD08BC-5CB5-471E-A40E-B7EFFC86E853}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {50CD08BC-5CB5-471E-A40E-B7EFFC86E853}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {50CD08BC-5CB5-471E-A40E-B7EFFC86E853}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {8DF05FEF-FBBB-4FBF-9595-44A270C972C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {8DF05FEF-FBBB-4FBF-9595-44A270C972C5}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {8DF05FEF-FBBB-4FBF-9595-44A270C972C5}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {8DF05FEF-FBBB-4FBF-9595-44A270C972C5}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {362A819C-58DD-4F6D-B23E-CEA104D7E78A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {362A819C-58DD-4F6D-B23E-CEA104D7E78A}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {362A819C-58DD-4F6D-B23E-CEA104D7E78A}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {362A819C-58DD-4F6D-B23E-CEA104D7E78A}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {658A2DCE-2702-42F7-8C71-CDCA9A05E6B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {658A2DCE-2702-42F7-8C71-CDCA9A05E6B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {658A2DCE-2702-42F7-8C71-CDCA9A05E6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {658A2DCE-2702-42F7-8C71-CDCA9A05E6B4}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {4122B5B6-5888-4F9B-AECE-28C98A0BB7A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {4122B5B6-5888-4F9B-AECE-28C98A0BB7A9}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {4122B5B6-5888-4F9B-AECE-28C98A0BB7A9}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {4122B5B6-5888-4F9B-AECE-28C98A0BB7A9}.Release|Any CPU.Build.0 = Release|Any CPU 76 | {C6FE3C36-AF81-41E8-88B0-3AAC9C56348F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 77 | {C6FE3C36-AF81-41E8-88B0-3AAC9C56348F}.Debug|Any CPU.Build.0 = Debug|Any CPU 78 | {C6FE3C36-AF81-41E8-88B0-3AAC9C56348F}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {C6FE3C36-AF81-41E8-88B0-3AAC9C56348F}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {BF2B363F-AB41-4BC8-A149-49EC59F06265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 81 | {BF2B363F-AB41-4BC8-A149-49EC59F06265}.Debug|Any CPU.Build.0 = Debug|Any CPU 82 | {BF2B363F-AB41-4BC8-A149-49EC59F06265}.Release|Any CPU.ActiveCfg = Release|Any CPU 83 | {BF2B363F-AB41-4BC8-A149-49EC59F06265}.Release|Any CPU.Build.0 = Release|Any CPU 84 | {9F66679A-191B-4551-ADBC-65A3430F9356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 85 | {9F66679A-191B-4551-ADBC-65A3430F9356}.Debug|Any CPU.Build.0 = Debug|Any CPU 86 | {9F66679A-191B-4551-ADBC-65A3430F9356}.Release|Any CPU.ActiveCfg = Release|Any CPU 87 | {9F66679A-191B-4551-ADBC-65A3430F9356}.Release|Any CPU.Build.0 = Release|Any CPU 88 | {6ADC9B53-4FB7-487A-8D61-CC4981C30269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 89 | {6ADC9B53-4FB7-487A-8D61-CC4981C30269}.Debug|Any CPU.Build.0 = Debug|Any CPU 90 | {6ADC9B53-4FB7-487A-8D61-CC4981C30269}.Release|Any CPU.ActiveCfg = Release|Any CPU 91 | {6ADC9B53-4FB7-487A-8D61-CC4981C30269}.Release|Any CPU.Build.0 = Release|Any CPU 92 | {F7226539-2B8F-492F-B9BD-DA81E298AE67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 93 | {F7226539-2B8F-492F-B9BD-DA81E298AE67}.Debug|Any CPU.Build.0 = Debug|Any CPU 94 | {F7226539-2B8F-492F-B9BD-DA81E298AE67}.Release|Any CPU.ActiveCfg = Release|Any CPU 95 | {F7226539-2B8F-492F-B9BD-DA81E298AE67}.Release|Any CPU.Build.0 = Release|Any CPU 96 | {D6542750-89CB-4D09-9E7B-EAAA392D4E5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 97 | {D6542750-89CB-4D09-9E7B-EAAA392D4E5D}.Debug|Any CPU.Build.0 = Debug|Any CPU 98 | {D6542750-89CB-4D09-9E7B-EAAA392D4E5D}.Release|Any CPU.ActiveCfg = Release|Any CPU 99 | {D6542750-89CB-4D09-9E7B-EAAA392D4E5D}.Release|Any CPU.Build.0 = Release|Any CPU 100 | {E41A6B84-9548-48D5-9908-AE2C8517EDC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 101 | {E41A6B84-9548-48D5-9908-AE2C8517EDC9}.Debug|Any CPU.Build.0 = Debug|Any CPU 102 | {E41A6B84-9548-48D5-9908-AE2C8517EDC9}.Release|Any CPU.ActiveCfg = Release|Any CPU 103 | {E41A6B84-9548-48D5-9908-AE2C8517EDC9}.Release|Any CPU.Build.0 = Release|Any CPU 104 | {BC44C424-5E6A-431B-80F9-5C597F50E042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 105 | {BC44C424-5E6A-431B-80F9-5C597F50E042}.Debug|Any CPU.Build.0 = Debug|Any CPU 106 | {BC44C424-5E6A-431B-80F9-5C597F50E042}.Release|Any CPU.ActiveCfg = Release|Any CPU 107 | {BC44C424-5E6A-431B-80F9-5C597F50E042}.Release|Any CPU.Build.0 = Release|Any CPU 108 | EndGlobalSection 109 | GlobalSection(SolutionProperties) = preSolution 110 | HideSolutionNode = FALSE 111 | EndGlobalSection 112 | GlobalSection(NestedProjects) = preSolution 113 | {8359AAA1-C41D-4FB7-9286-C8FBC0DC9E0F} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 114 | {50CD08BC-5CB5-471E-A40E-B7EFFC86E853} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 115 | {8DF05FEF-FBBB-4FBF-9595-44A270C972C5} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 116 | {362A819C-58DD-4F6D-B23E-CEA104D7E78A} = {C2A80735-2797-474C-9879-126B562DD2F5} 117 | {658A2DCE-2702-42F7-8C71-CDCA9A05E6B4} = {C2A80735-2797-474C-9879-126B562DD2F5} 118 | {4122B5B6-5888-4F9B-AECE-28C98A0BB7A9} = {C2A80735-2797-474C-9879-126B562DD2F5} 119 | {C6FE3C36-AF81-41E8-88B0-3AAC9C56348F} = {B83B1F14-CC19-4B40-B0F3-28B18CB56760} 120 | {BF2B363F-AB41-4BC8-A149-49EC59F06265} = {B83B1F14-CC19-4B40-B0F3-28B18CB56760} 121 | {9F66679A-191B-4551-ADBC-65A3430F9356} = {B83B1F14-CC19-4B40-B0F3-28B18CB56760} 122 | {6ADC9B53-4FB7-487A-8D61-CC4981C30269} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 123 | {F7226539-2B8F-492F-B9BD-DA81E298AE67} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 124 | {D6542750-89CB-4D09-9E7B-EAAA392D4E5D} = {84C88291-7FC8-47AC-84FA-9CF5DF39028C} 125 | {E41A6B84-9548-48D5-9908-AE2C8517EDC9} = {C2A80735-2797-474C-9879-126B562DD2F5} 126 | {BC44C424-5E6A-431B-80F9-5C597F50E042} = {B83B1F14-CC19-4B40-B0F3-28B18CB56760} 127 | EndGlobalSection 128 | GlobalSection(ExtensibilityGlobals) = postSolution 129 | SolutionGuid = {A022B3C8-E866-480E-82A5-17935BA812CC} 130 | EndGlobalSection 131 | EndGlobal 132 | --------------------------------------------------------------------------------