├── .gitignore ├── Demos └── Messenger │ ├── Messenger.csproj │ └── Program.cs ├── Implementation ├── ObjectTransport.Serializer.JSON │ ├── JSONserializer.cs │ ├── ObjectTransport.JSON.csproj │ └── ObjectTransportAssemblyLine_JSONExtension.cs ├── ObjectTransport.Serializer.protobuf │ ├── ObjectTransport.Protobuf.csproj │ ├── ObjectTransportAssemblyLine_protobufExtension.cs │ └── ProtobufSerializer.cs ├── ObjectTransport.TCP │ ├── ObjectTransport.TCP.csproj │ ├── ObjectTransportFactoryTCPExtension.cs │ ├── TCPClientChannel.cs │ ├── TCPMessage.cs │ ├── TCPServerChannel.cs │ └── TCPUtilities.cs └── ObjectTransport.UDP │ ├── ObjectTransport.UDP.csproj │ ├── ObjectTransportFactoryUDPExtension.cs │ ├── UDPClientChannel.cs │ └── UDPServerChannel.cs ├── LICENSE ├── LICENSE.LiteNetLib.txt ├── ObjectTransport.sln ├── ObjectTransport.tests ├── NetworkChannel.tests │ ├── INetworkChannelGenericTests.cs │ ├── TCPNetworkChannelGenericTests.cs │ ├── UDPNetworkChannelGenericTests.cs │ └── Utilities │ │ └── TCPNetworkChannelFactory.cs ├── ObjectTransport.Test.csproj ├── ObjectTransport_OnConnect.tests.cs ├── ObjectTransport_Receive.tests.cs ├── ObjectTransport_Send.tests.cs ├── ObjectTransport_TimeOut.tests.cs ├── Serializer │ ├── Protobuf_MockObjectMessage.cs │ └── Protobuf_Serializer.tests.cs └── Utilities │ ├── MockNetworkChannelFactory.cs │ ├── MockObjectMessage.cs │ ├── MockObjectMessageWithBinary.cs │ ├── TestObjectTransportFactory.cs │ └── Utilities.cs ├── ObjectTransport ├── Client.cs ├── Factory │ ├── ObjectTransportAssemblyLine.cs │ └── ObjectTransportFactory.cs ├── IObjectTransport.cs ├── MessageReceive.cs ├── MessageResponseHandle.cs ├── MessageSend.cs ├── Network Channels │ └── INetworkChannel.cs ├── ObjectTransport.cs ├── ObjectTransport.csproj ├── ObjectTransportException.cs ├── PayLoad │ ├── QueuedMessage.cs │ ├── ReceivedConnection.cs │ └── ReceivedMessage.cs ├── ReceivedMessageHandle.cs └── Serializer │ └── ISerializer.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # Benchmark Results 46 | BenchmarkDotNet.Artifacts/ 47 | 48 | # .NET Core 49 | project.lock.json 50 | project.fragment.lock.json 51 | artifacts/ 52 | **/Properties/launchSettings.json 53 | 54 | *_i.c 55 | *_p.c 56 | *_i.h 57 | *.ilk 58 | *.meta 59 | *.obj 60 | *.pch 61 | *.pdb 62 | *.pgc 63 | *.pgd 64 | *.rsp 65 | *.sbr 66 | *.tlb 67 | *.tli 68 | *.tlh 69 | *.tmp 70 | *.tmp_proj 71 | *.log 72 | *.vspscc 73 | *.vssscc 74 | .builds 75 | *.pidb 76 | *.svclog 77 | *.scc 78 | 79 | # Chutzpah Test files 80 | _Chutzpah* 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opendb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | *.VC.db 91 | *.VC.VC.opendb 92 | 93 | # Visual Studio profiler 94 | *.psess 95 | *.vsp 96 | *.vspx 97 | *.sap 98 | 99 | # TFS 2012 Local Workspace 100 | $tf/ 101 | 102 | # Guidance Automation Toolkit 103 | *.gpState 104 | 105 | # ReSharper is a .NET coding add-in 106 | _ReSharper*/ 107 | *.[Rr]e[Ss]harper 108 | *.DotSettings.user 109 | 110 | # JustCode is a .NET coding add-in 111 | .JustCode 112 | 113 | # TeamCity is a build add-in 114 | _TeamCity* 115 | 116 | # DotCover is a Code Coverage Tool 117 | *.dotCover 118 | 119 | # Visual Studio code coverage results 120 | *.coverage 121 | *.coveragexml 122 | 123 | # NCrunch 124 | _NCrunch_* 125 | .*crunch*.local.xml 126 | nCrunchTemp_* 127 | 128 | # MightyMoose 129 | *.mm.* 130 | AutoTest.Net/ 131 | 132 | # Web workbench (sass) 133 | .sass-cache/ 134 | 135 | # Installshield output folder 136 | [Ee]xpress/ 137 | 138 | # DocProject is a documentation generator add-in 139 | DocProject/buildhelp/ 140 | DocProject/Help/*.HxT 141 | DocProject/Help/*.HxC 142 | DocProject/Help/*.hhc 143 | DocProject/Help/*.hhk 144 | DocProject/Help/*.hhp 145 | DocProject/Help/Html2 146 | DocProject/Help/html 147 | 148 | # Click-Once directory 149 | publish/ 150 | 151 | # Publish Web Output 152 | *.[Pp]ublish.xml 153 | *.azurePubxml 154 | # Note: Comment the next line if you want to checkin your web deploy settings, 155 | # but database connection strings (with potential passwords) will be unencrypted 156 | *.pubxml 157 | *.publishproj 158 | 159 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 160 | # checkin your Azure Web App publish settings, but sensitive information contained 161 | # in these scripts will be unencrypted 162 | PublishScripts/ 163 | 164 | # NuGet Packages 165 | *.nupkg 166 | # The packages folder can be ignored because of Package Restore 167 | **/packages/* 168 | # except build/, which is used as an MSBuild target. 169 | !**/packages/build/ 170 | # Uncomment if necessary however generally it will be regenerated when needed 171 | #!**/packages/repositories.config 172 | # NuGet v3's project.json files produces more ignorable files 173 | *.nuget.props 174 | *.nuget.targets 175 | 176 | # Microsoft Azure Build Output 177 | csx/ 178 | *.build.csdef 179 | 180 | # Microsoft Azure Emulator 181 | ecf/ 182 | rcf/ 183 | 184 | # Windows Store app package directories and files 185 | AppPackages/ 186 | BundleArtifacts/ 187 | Package.StoreAssociation.xml 188 | _pkginfo.txt 189 | *.appx 190 | 191 | # Visual Studio cache files 192 | # files ending in .cache can be ignored 193 | *.[Cc]ache 194 | # but keep track of directories ending in .cache 195 | !*.[Cc]ache/ 196 | 197 | # Others 198 | ClientBin/ 199 | ~$* 200 | *~ 201 | *.dbmdl 202 | *.dbproj.schemaview 203 | *.jfm 204 | *.pfx 205 | *.publishsettings 206 | orleans.codegen.cs 207 | 208 | # Since there are multiple workflows, uncomment next line to ignore bower_components 209 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 210 | #bower_components/ 211 | 212 | # RIA/Silverlight projects 213 | Generated_Code/ 214 | 215 | # Backup & report files from converting an old project file 216 | # to a newer Visual Studio version. Backup files are not needed, 217 | # because we have git ;-) 218 | _UpgradeReport_Files/ 219 | Backup*/ 220 | UpgradeLog*.XML 221 | UpgradeLog*.htm 222 | 223 | # SQL Server files 224 | *.mdf 225 | *.ldf 226 | *.ndf 227 | 228 | # Business Intelligence projects 229 | *.rdl.data 230 | *.bim.layout 231 | *.bim_*.settings 232 | 233 | # Microsoft Fakes 234 | FakesAssemblies/ 235 | 236 | # GhostDoc plugin setting file 237 | *.GhostDoc.xml 238 | 239 | # Node.js Tools for Visual Studio 240 | .ntvs_analysis.dat 241 | node_modules/ 242 | 243 | # Typescript v1 declaration files 244 | typings/ 245 | 246 | # Visual Studio 6 build log 247 | *.plg 248 | 249 | # Visual Studio 6 workspace options file 250 | *.opt 251 | 252 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 253 | *.vbw 254 | 255 | # Visual Studio LightSwitch build output 256 | **/*.HTMLClient/GeneratedArtifacts 257 | **/*.DesktopClient/GeneratedArtifacts 258 | **/*.DesktopClient/ModelManifest.xml 259 | **/*.Server/GeneratedArtifacts 260 | **/*.Server/ModelManifest.xml 261 | _Pvt_Extensions 262 | 263 | # Paket dependency manager 264 | .paket/paket.exe 265 | paket-files/ 266 | 267 | # FAKE - F# Make 268 | .fake/ 269 | 270 | # JetBrains Rider 271 | .idea/ 272 | *.sln.iml 273 | 274 | # CodeRush 275 | .cr/ 276 | 277 | # Python Tools for Visual Studio (PTVS) 278 | __pycache__/ 279 | *.pyc 280 | 281 | # Cake - Uncomment if you are using it 282 | # tools/** 283 | # !tools/packages.config 284 | 285 | # Tabs Studio 286 | *.tss 287 | 288 | # Telerik's JustMock configuration file 289 | *.jmconfig 290 | 291 | # BizTalk build output 292 | *.btp.cs 293 | *.btm.cs 294 | *.odx.cs 295 | *.xsd.cs -------------------------------------------------------------------------------- /Demos/Messenger/Messenger.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Demos/Messenger/Program.cs: -------------------------------------------------------------------------------- 1 | using OTransport.NetworkChannel.TCP; 2 | using OTransport; 3 | using System; 4 | using OTransport.NetworkChannel.UDP; 5 | using OTransport.Serializer.JSON; 6 | 7 | namespace Messenger 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | Console.WriteLine("Welcome to this simple Chat room!"); 14 | Console.WriteLine("Would you like to:"); 15 | Console.WriteLine("1) Create a TCP server"); 16 | Console.WriteLine("2) Connect to TCP server"); 17 | 18 | IObjectTransport transport; 19 | 20 | string answer = Console.ReadLine(); 21 | 22 | //Create Server 23 | if (answer == "1") 24 | { 25 | transport = ObjectTransport.Factory.CreateTCPServer() 26 | .UseJSONserialization() 27 | .Build() 28 | .Start("127.0.0.1", 1234); 29 | 30 | //Receive a receive an object of type Message. c= Client, m = Object that was received 31 | transport.Receive((c, m) => 32 | { 33 | Console.WriteLine("{0} - {1}", c.IPAddress, m.Body); 34 | 35 | //We want all clients to see the message that was sent to the server. 36 | //However, we do not want the original client to receive the message. 37 | transport.Send(m) 38 | .ToAllExcept(c) 39 | .Execute(); 40 | 41 | }) 42 | .Execute(); 43 | } 44 | else 45 | { 46 | //Create Client 47 | transport = ObjectTransport.Factory.CreateTCPClient() 48 | .UseJSONserialization() 49 | .Build() 50 | .Start("127.0.0.1", 1234); 51 | 52 | 53 | transport.Receive((c, m) => 54 | { 55 | Console.WriteLine("{0} - {1}", c.IPAddress, m.Body); 56 | } 57 | ) 58 | .Execute(); 59 | } 60 | 61 | //Write to console when a client connects 62 | transport.OnClientConnect(c => Console.WriteLine("{0} - Client connected", c.IPAddress)); 63 | 64 | //Write to console when a client disconnects 65 | transport.OnClientDisconnect(c => Console.WriteLine("{0} - Client disconnected", c.IPAddress)); 66 | 67 | 68 | Console.WriteLine("Begin Chatting!"); 69 | 70 | string message; 71 | while (true) 72 | { 73 | message = Console.ReadLine(); 74 | 75 | if (message == "exit") 76 | break; 77 | 78 | transport.Send(new Message() { Body = message }) 79 | .ToAll() 80 | .Execute(); 81 | } 82 | } 83 | } 84 | public class Message 85 | { 86 | public string Body { get; set; } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.JSON/JSONserializer.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using OTransport.Serializer; 3 | using System; 4 | 5 | namespace OTransport.Serializer.JSON 6 | { 7 | public class JSONserializer : ISerializer 8 | { 9 | 10 | public object Deserialize(string objectPayload, Type objectType) 11 | { 12 | return JsonConvert.DeserializeObject(objectPayload,objectType); 13 | } 14 | 15 | public string Serialize(object obj) 16 | { 17 | return JsonConvert.SerializeObject(obj); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.JSON/ObjectTransport.JSON.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.6;netcoreapp1.1;net46 5 | OT.Serializer.JSON 6 | OTransport.Serializer.JSON 7 | ObjectTransport.JSON 8 | 0.2.1 9 | Rhyno van der Sluijs 10 | This package contains the JSON serialization implementation for the ObjectTransport framework. 11 | Please see the following link for more information about installing ObjectTransport: 12 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 13 | 14 | false 15 | 16 | Update to Nuget package description. 17 | 18 | 19 | https://github.com/RhynoVDS/ObjectTransport 20 | TCP Server Object networking UDP 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.JSON/ObjectTransportAssemblyLine_JSONExtension.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Serializer.JSON; 2 | using OTransport.Factory; 3 | 4 | namespace OTransport.Serializer.JSON 5 | { 6 | public static class ObjectTransportAssemblyLine_JSONExtension 7 | { 8 | /// 9 | /// Use Json serialization to serialize objects 10 | /// 11 | /// 12 | public static ObjectTransportAssemblyLine UseJSONserialization(this ObjectTransportAssemblyLine objectTranposrtAssemblyLine) 13 | { 14 | var jsonSerialization = new JSONserializer(); 15 | objectTranposrtAssemblyLine.SetSerializer(jsonSerialization); 16 | 17 | return objectTranposrtAssemblyLine; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.protobuf/ObjectTransport.Protobuf.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.6;netcoreapp1.1;net46 5 | OTransport.Serializer.protobuf 6 | ObjectTransport.Protobuf 7 | 0.2.1 8 | Rhyno van der Sluijs 9 | This package contains the Protobuf serialization implementation for the ObjectTransport framework. 10 | Please see the following link for more information about installing ObjectTransport: 11 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 12 | 13 | false 14 | 15 | Update to Nuget package description. 16 | 17 | 18 | https://github.com/RhynoVDS/ObjectTransport 19 | TCP Server Object networking UDP 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.protobuf/ObjectTransportAssemblyLine_protobufExtension.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Factory; 2 | using OTransport.Serializer.protobuf; 3 | 4 | namespace OTransport.Serializer.protobuf 5 | { 6 | public static class ObjectTransportAssemblyLine_protobufExtension 7 | { 8 | /// 9 | /// Use Protobuf Serialization to serialize objects 10 | /// 11 | /// 12 | public static ObjectTransportAssemblyLine UseProtobufSerialization(this ObjectTransportAssemblyLine objectTranposrtAssemblyLine) 13 | { 14 | var protobufSerialization = new ProtobufSerializer(); 15 | objectTranposrtAssemblyLine.SetSerializer(protobufSerialization); 16 | 17 | return objectTranposrtAssemblyLine; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.Serializer.protobuf/ProtobufSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace OTransport.Serializer.protobuf 6 | { 7 | public class ProtobufSerializer : ISerializer 8 | { 9 | public object Deserialize(string objectPayload, Type objectType) 10 | { 11 | byte[] byteArray = Encoding.UTF8.GetBytes(objectPayload); 12 | //byte[] byteArray = Encoding.ASCII.GetBytes(contents); 13 | MemoryStream stream = new MemoryStream(byteArray); 14 | return ProtoBuf.Serializer.Deserialize(objectType, stream); 15 | } 16 | 17 | public string Serialize(object obj) 18 | { 19 | using (MemoryStream stream = new MemoryStream()) 20 | { 21 | ProtoBuf.Serializer.Serialize(stream, obj); 22 | return System.Text.Encoding.UTF8.GetString(stream.ToArray()); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/ObjectTransport.TCP.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.6;netcoreapp1.1;net46 5 | ObjectTransport.TCP 6 | PackageReference 7 | true 8 | OTransport.NetworkChannel.TCP 9 | ObjectTransport.TCP 10 | 0.2.4 11 | Rhyno van der Sluijs 12 | This package contains the TCP network channel implementation for the ObjectTransport framework. This package allows you to send and receive objects over TCP. 13 | Please see the following link for more information about installing ObjectTransport: 14 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 15 | 16 | false 17 | 18 | This release introduces the DisconnectClient function which allows you to disconnect a connected client. 19 | 20 | 21 | https://github.com/RhynoVDS/ObjectTransport 22 | TCP Server Object networking UDP 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 4.0.0 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/ObjectTransportFactoryTCPExtension.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Factory; 2 | 3 | namespace OTransport.NetworkChannel.TCP 4 | { 5 | public static class ObjectTransportFactoryTCPExtension 6 | { 7 | /// 8 | /// Create a TCP server. This network channel only supports reliable communication. 9 | /// 10 | /// the IP address to start the server on 11 | /// the port to listen on 12 | /// 13 | public static ObjectTransportAssemblyLine CreateTCPServer(this ObjectTransportFactory o) 14 | { 15 | TCPServerChannel server = new TCPServerChannel(); 16 | var assemblyLine = new ObjectTransportAssemblyLine(); 17 | assemblyLine.SetNetworkChannel(server); 18 | assemblyLine.SetReliableTransport(); 19 | 20 | return assemblyLine; 21 | } 22 | 23 | /// 24 | /// Create a TCP client. This network channel only supports reliable communication. 25 | /// 26 | /// the IP address to start the server on 27 | /// the port to listen on 28 | /// 29 | public static ObjectTransportAssemblyLine CreateTCPClient(this ObjectTransportFactory o) 30 | { 31 | TCPClientChannel client = new TCPClientChannel(); 32 | 33 | var assemblyLine = new ObjectTransportAssemblyLine(); 34 | assemblyLine.SetNetworkChannel(client); 35 | assemblyLine.SetReliableTransport(); 36 | 37 | return assemblyLine; 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/TCPClientChannel.cs: -------------------------------------------------------------------------------- 1 | using OTransport; 2 | using OTransport.NetworkChannel.TCP; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace OTransport.NetworkChannel.TCP 12 | { 13 | public class TCPClientChannel : INetworkChannel 14 | { 15 | private IPAddress IPAddress; 16 | private int EndPointPort; 17 | private int _LocalPort; 18 | private TcpClient tcpClient = null; 19 | private Client client = null; 20 | 21 | private Action onReceiveCallback = null; 22 | private Task ListenTask = null; 23 | Action onConnectCallBack = null; 24 | Action onDisconnectCallBack = null; 25 | 26 | public int LocalPort { get { return _LocalPort; } } 27 | 28 | private void ListenThread() 29 | { 30 | Task clientTask = new Task((c) => 31 | { 32 | while (true) 33 | { 34 | Byte[] bytes; 35 | try 36 | { 37 | if (!TCPUtilities.IsConnected(tcpClient)) 38 | throw new Exception("Client Disconnected"); 39 | 40 | NetworkStream ns = tcpClient.GetStream(); 41 | if (tcpClient.ReceiveBufferSize > 0) 42 | { 43 | bytes = new byte[tcpClient.ReceiveBufferSize]; 44 | ns.Read(bytes, 0, tcpClient.ReceiveBufferSize); 45 | string msg = Encoding.ASCII.GetString(bytes); 46 | 47 | ReceivedMessage message = new ReceivedMessage((Client)c, msg); 48 | 49 | if (onReceiveCallback != null) 50 | onReceiveCallback.Invoke(message); 51 | } 52 | } 53 | catch 54 | { 55 | if (onDisconnectCallBack != null) 56 | onDisconnectCallBack.Invoke((Client)c); 57 | 58 | break; 59 | } 60 | 61 | } 62 | }, client); 63 | clientTask.Start(); 64 | ListenTask = clientTask; 65 | } 66 | 67 | private void ConnectToServer() 68 | { 69 | tcpClient.ConnectAsync(IPAddress, EndPointPort).Wait(); 70 | } 71 | public void OnClientConnect(Action callBack) 72 | { 73 | onConnectCallBack = callBack; 74 | if (client != null) 75 | onConnectCallBack.Invoke(client); 76 | } 77 | 78 | public void OnReceive(Action callBack) 79 | { 80 | onReceiveCallback = callBack; 81 | } 82 | 83 | public void SendReliable(Client client, string message) 84 | { 85 | } 86 | 87 | public void Stop() 88 | { 89 | if (tcpClient !=null && tcpClient.Connected) 90 | { 91 | tcpClient.Client.Shutdown(SocketShutdown.Both); 92 | tcpClient.Client.Dispose(); 93 | } 94 | } 95 | 96 | public void OnClientDisconnect(Action callBack) 97 | { 98 | onDisconnectCallBack = callBack; 99 | } 100 | 101 | public void SetReliable() 102 | { 103 | } 104 | 105 | public void SetUnreliable() 106 | { 107 | throw new NotSupportedException("This network channel does not support un-reliable sending"); 108 | } 109 | 110 | public void Send(Client client, string payload) 111 | { 112 | Byte[] data = System.Text.Encoding.ASCII.GetBytes(payload); 113 | 114 | NetworkStream stream = tcpClient.GetStream(); 115 | 116 | stream.Write(data, 0, data.Length); 117 | } 118 | 119 | public void DisconnectClient(params Client[] clients) 120 | { 121 | //This is the client, we just stop the client. 122 | Stop(); 123 | } 124 | 125 | public void Start(string ipAddress, int endpointPort) 126 | { 127 | tcpClient = new TcpClient(); 128 | client = new Client(ipAddress, endpointPort); 129 | IPAddress = IPAddress.Parse(ipAddress); 130 | EndPointPort = endpointPort; 131 | 132 | ConnectToServer(); 133 | _LocalPort = ((IPEndPoint)tcpClient.Client.LocalEndPoint).Port; 134 | ListenThread(); 135 | 136 | if (client != null) 137 | onConnectCallBack?.Invoke(client); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/TCPMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport.NetworkChannel.TCP 6 | { 7 | public class TCPMessage 8 | { 9 | public const string KeepAlive = ""; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/TCPServerChannel.cs: -------------------------------------------------------------------------------- 1 | using OTransport; 2 | using OTransport.NetworkChannel.TCP; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace OTransport.NetworkChannel.TCP 13 | { 14 | public class TCPServerChannel : INetworkChannel 15 | { 16 | private Dictionary ClientToTCPMap = new Dictionary(); 17 | private IPAddress IPAddress; 18 | private TcpListener Server; 19 | private int _LocalPort; 20 | 21 | Action onReceiveCallback = null; 22 | List clientTasks = new List(); 23 | Action onConnectCallBack = null; 24 | Action onDisconnectCallBack = null; 25 | 26 | public int LocalPort { get { return _LocalPort; } } 27 | 28 | public void Stop() 29 | { 30 | var clients = ClientToTCPMap.Keys.ToArray(); 31 | foreach(var client in clients) 32 | { 33 | ClientToTCPMap[client].Client.Shutdown(SocketShutdown.Both); 34 | ClientToTCPMap[client].Client.Dispose(); 35 | ClientToTCPMap.Remove(client); 36 | } 37 | Server?.Stop(); 38 | } 39 | private void StartListeningThread() 40 | { 41 | Thread listenConnection = new Thread(async() => 42 | { 43 | while (true) 44 | { 45 | TcpClient tcpClient = null; 46 | try 47 | { 48 | tcpClient = await Server.AcceptTcpClientAsync(); 49 | } 50 | catch (ObjectDisposedException) { break; } 51 | 52 | string[] addressArray = tcpClient.Client.RemoteEndPoint.ToString().Split(':'); 53 | Client client = new Client(addressArray[0], int.Parse(addressArray[1])); 54 | ClientToTCPMap.Add(client, tcpClient); 55 | 56 | if(onConnectCallBack !=null) 57 | onConnectCallBack.Invoke(client); 58 | 59 | 60 | Task clientTask = new Task(async (c) => 61 | { 62 | Byte[] bytes; 63 | while (true) 64 | { 65 | try 66 | { 67 | if(!TCPUtilities.IsConnected(tcpClient)) 68 | throw new Exception("Client Disconnected"); 69 | 70 | NetworkStream ns = tcpClient.GetStream(); 71 | 72 | if (tcpClient.ReceiveBufferSize > 0) 73 | { 74 | string receivedMessage = string.Empty; 75 | 76 | do 77 | { 78 | bytes = new byte[tcpClient.ReceiveBufferSize]; 79 | ns.Read(bytes, 0, tcpClient.ReceiveBufferSize); 80 | string msg = Encoding.ASCII.GetString(bytes); 81 | receivedMessage += msg; 82 | await Task.Delay(1); 83 | } 84 | while (ns.DataAvailable); 85 | 86 | ReceivedMessage message = null; 87 | message = new ReceivedMessage((Client)c, receivedMessage); 88 | 89 | 90 | if (onReceiveCallback != null) 91 | onReceiveCallback.Invoke(message); 92 | } 93 | } 94 | catch 95 | { 96 | ClientToTCPMap.Remove((Client)c); 97 | if (onDisconnectCallBack != null) 98 | onDisconnectCallBack.Invoke((Client)c); 99 | break; 100 | } 101 | 102 | } 103 | },client); 104 | clientTask.Start(); 105 | clientTasks.Add(clientTask); 106 | } 107 | }); 108 | listenConnection.Start(); 109 | } 110 | 111 | public void OnClientConnect(Action callBack) 112 | { 113 | onConnectCallBack = callBack; 114 | } 115 | 116 | public void OnReceive(Action callBack) 117 | { 118 | onReceiveCallback = callBack; 119 | } 120 | 121 | public void OnClientDisconnect(Action callBack) 122 | { 123 | onDisconnectCallBack = callBack; 124 | } 125 | 126 | public void SetReliable() 127 | { 128 | } 129 | 130 | public void SetUnreliable() 131 | { 132 | throw new NotSupportedException("This network channel does not support un-reliable sending"); 133 | } 134 | 135 | public void Send(Client client, string payload) 136 | { 137 | var tcpClient = ClientToTCPMap[client]; 138 | Byte[] data = System.Text.Encoding.ASCII.GetBytes(payload); 139 | 140 | NetworkStream stream = tcpClient.GetStream(); 141 | 142 | stream.Write(data, 0, data.Length); 143 | } 144 | 145 | public void DisconnectClient(params Client[] clients) 146 | { 147 | foreach(var client in clients) 148 | { 149 | TcpClient tcpclient = ClientToTCPMap[client]; 150 | tcpclient.Dispose(); 151 | ClientToTCPMap.Remove(client); 152 | } 153 | } 154 | 155 | public void Start(string ipaddress, int port) 156 | { 157 | IPAddress = IPAddress.Parse(ipaddress); 158 | 159 | Server = new TcpListener(IPAddress, port); 160 | Server.Start(); 161 | _LocalPort = int.Parse(Server.LocalEndpoint.ToString().Split(':')[1]); 162 | 163 | StartListeningThread(); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.TCP/TCPUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Sockets; 4 | using System.Text; 5 | 6 | namespace OTransport.NetworkChannel.TCP 7 | { 8 | class TCPUtilities 9 | { 10 | public static bool IsConnected(TcpClient tcpClient) 11 | { 12 | try 13 | { 14 | if (tcpClient != null && tcpClient.Client != null && tcpClient.Client.Connected) 15 | { 16 | 17 | // Detect if client disconnected 18 | if (tcpClient.Client.Poll(0, SelectMode.SelectRead)) 19 | { 20 | byte[] buff = new byte[1]; 21 | if (tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0) 22 | { 23 | // Client disconnected 24 | return false; 25 | } 26 | else 27 | { 28 | return true; 29 | } 30 | } 31 | 32 | return true; 33 | } 34 | else 35 | { 36 | return false; 37 | } 38 | } 39 | catch 40 | { 41 | return false; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.UDP/ObjectTransport.UDP.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.6;netcoreapp1.1;net46 5 | ObjectTransport.UDP 6 | OTransport.NetworkChannel.UDP 7 | ObjectTransport.UDP 8 | 0.2.3 9 | Rhyno van der Sluijs 10 | This package contains the UDP network channel implementation for the ObjectTransport framework. This package allows you to send and receive objects over UDP. 11 | Please see the following link for more information about installing ObjectTransport: 12 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 13 | 14 | false 15 | 16 | This release introduces the DisconnectClient function which allows you to disconnect a connected client. 17 | 18 | 19 | TCP Server Object networking UDP 20 | https://github.com/RhynoVDS/ObjectTransport 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.UDP/ObjectTransportFactoryUDPExtension.cs: -------------------------------------------------------------------------------- 1 | using OTransport; 2 | using OTransport.Factory; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace OTransport.NetworkChannel.UDP 8 | { 9 | public static class ObjectTransportFactoryUDPExtension 10 | { 11 | /// 12 | /// Create a UDP server. This supports reliable and unreliable communications. Defaults to unreliable. 13 | /// 14 | /// the IP address to start the server on 15 | /// the port to listen on 16 | /// 17 | public static ObjectTransportAssemblyLine CreateUDPServer(this ObjectTransportFactory o) 18 | { 19 | UDPServerChannel server = new UDPServerChannel(); 20 | var assemblyLine = new ObjectTransportAssemblyLine(); 21 | assemblyLine.SetNetworkChannel(server); 22 | assemblyLine.SetUnreliableTransport(); 23 | 24 | return assemblyLine; 25 | } 26 | 27 | /// 28 | /// Create a UDP client. This supports reliable and unreliable communications. Defaults to unreliable. 29 | /// 30 | /// the IP address to start the server on 31 | /// the port to listen on 32 | /// 33 | public static ObjectTransportAssemblyLine CreateUDPClient(this ObjectTransportFactory o) 34 | { 35 | var client = new UDPClientChannel(); 36 | var assemblyLine = new ObjectTransportAssemblyLine(); 37 | assemblyLine.SetNetworkChannel(client); 38 | assemblyLine.SetUnreliableTransport(); 39 | 40 | return assemblyLine; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.UDP/UDPClientChannel.cs: -------------------------------------------------------------------------------- 1 | using LiteNetLib; 2 | using LiteNetLib.Utils; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace OTransport.NetworkChannel.UDP 13 | { 14 | public class UDPClientChannel : INetworkChannel 15 | { 16 | //This should technically only ever have on entry as this is the client. 17 | private Dictionary ClientToNetPeerMap = new Dictionary(); 18 | private IPAddress IPAddress; 19 | 20 | private EventBasedNetListener listener; 21 | private NetManager clientUDP; 22 | 23 | private int _LocalPort; 24 | private bool ReliableTransport = false; 25 | 26 | 27 | Action onReceiveCallback = null; 28 | Action onConnectCallBack = null; 29 | Action onDisconnectCallBack = null; 30 | 31 | public int LocalPort { get { return _LocalPort; } } 32 | 33 | public void Stop() 34 | { 35 | if(clientUDP?.IsRunning != null && clientUDP?.IsRunning == true) 36 | clientUDP?.Stop(); 37 | 38 | foreach (Client client in ClientToNetPeerMap.Keys) 39 | { 40 | onDisconnectCallBack?.Invoke(client); 41 | } 42 | } 43 | private void WaitTillConnectionMade() 44 | { 45 | 46 | int count = 0; 47 | 48 | //Wait until the connection is made and make sure that it doesn't time out. 49 | while(ClientToNetPeerMap.Count() ==0 && count < 1000000000) 50 | { 51 | count += 1; 52 | } 53 | } 54 | private Client GetClientRecord(NetPeer peer) 55 | { 56 | Client client = ClientToNetPeerMap.First(o => o.Value == peer).Key; 57 | return client; 58 | } 59 | 60 | public void OnClientConnect(Action callBack) 61 | { 62 | onConnectCallBack = callBack; 63 | if (ClientToNetPeerMap.Count() > 0) 64 | onConnectCallBack.Invoke(ClientToNetPeerMap.First().Key); 65 | } 66 | 67 | public void OnReceive(Action callBack) 68 | { 69 | onReceiveCallback = callBack; 70 | } 71 | 72 | public void OnClientDisconnect(Action callBack) 73 | { 74 | onDisconnectCallBack = callBack; 75 | } 76 | 77 | public void SetReliable() 78 | { 79 | ReliableTransport = true; 80 | } 81 | 82 | public void SetUnreliable() 83 | { 84 | ReliableTransport = false; 85 | } 86 | 87 | public void Send(Client client, string payload) 88 | { 89 | var netPeer = this.ClientToNetPeerMap[client]; 90 | 91 | NetDataWriter writer = new NetDataWriter(); 92 | writer.Put(payload); 93 | if (ReliableTransport) 94 | netPeer.Send(writer, SendOptions.ReliableOrdered); 95 | else 96 | netPeer.Send(writer, SendOptions.Sequenced); 97 | } 98 | 99 | public void DisconnectClient(params Client[] clients) 100 | { 101 | //This is the client so stop the connection completely. 102 | Stop(); 103 | } 104 | 105 | public void Start(string ipaddress, int port) 106 | { 107 | listener = new EventBasedNetListener(); 108 | clientUDP = new NetManager(listener, "ConnectionKey"); 109 | clientUDP.UnsyncedEvents = true; 110 | clientUDP.Start(); 111 | clientUDP.Connect(ipaddress, port); 112 | 113 | listener.PeerDisconnectedEvent += (c,i) => 114 | { 115 | Client client = GetClientRecord(c); 116 | onDisconnectCallBack.Invoke(client); 117 | }; 118 | 119 | listener.PeerConnectedEvent += c => 120 | { 121 | Client client = new Client(c.EndPoint.Host, c.EndPoint.Port); 122 | ClientToNetPeerMap.Add(client, c); 123 | onConnectCallBack?.Invoke(client); 124 | }; 125 | 126 | listener.NetworkReceiveEvent += (fromPeer, dataReader) => 127 | { 128 | Client client = GetClientRecord(fromPeer); 129 | var payload = dataReader.GetString(); 130 | ReceivedMessage receivedMessage = new ReceivedMessage(client, payload); 131 | onReceiveCallback.Invoke(receivedMessage); 132 | }; 133 | 134 | clientUDP.PollEvents(); 135 | 136 | WaitTillConnectionMade(); 137 | this._LocalPort = clientUDP.LocalPort; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Implementation/ObjectTransport.UDP/UDPServerChannel.cs: -------------------------------------------------------------------------------- 1 | using LiteNetLib; 2 | using LiteNetLib.Utils; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace OTransport.NetworkChannel.UDP 13 | { 14 | public class UDPServerChannel : INetworkChannel 15 | { 16 | private Dictionary ClientToNetPeerMap = new Dictionary(); 17 | private IPAddress IPAddress; 18 | 19 | private EventBasedNetListener listener; 20 | private NetManager server; 21 | 22 | private bool ReliableTransport = false; 23 | private int _LocalPort; 24 | public int LocalPort { get { return _LocalPort; } } 25 | 26 | 27 | List clientTasks = new List(); 28 | Action onReceiveCallback = null; 29 | Action onConnectCallBack = null; 30 | Action onDisconnectCallBack = null; 31 | 32 | 33 | public void Stop() 34 | { 35 | foreach (var keypair in ClientToNetPeerMap) 36 | { 37 | server.DisconnectPeer(keypair.Value); 38 | server.Stop(); 39 | } 40 | } 41 | private Client GetClientRecord(NetPeer peer) 42 | { 43 | Client client = ClientToNetPeerMap.First(o => o.Value == peer).Key; 44 | return client; 45 | } 46 | 47 | public void OnClientConnect(Action callBack) 48 | { 49 | onConnectCallBack = callBack; 50 | } 51 | 52 | public void OnReceive(Action callBack) 53 | { 54 | onReceiveCallback = callBack; 55 | } 56 | 57 | public void OnClientDisconnect(Action callBack) 58 | { 59 | onDisconnectCallBack = callBack; 60 | } 61 | 62 | public void SetReliable() 63 | { 64 | ReliableTransport = true; 65 | } 66 | 67 | public void SetUnreliable() 68 | { 69 | ReliableTransport = false; 70 | } 71 | 72 | public void Send(Client client, string payload) 73 | { 74 | var netPeer = this.ClientToNetPeerMap[client]; 75 | NetDataWriter writer = new NetDataWriter(); 76 | writer.Put(payload); 77 | 78 | if(ReliableTransport) 79 | netPeer.Send(writer,SendOptions.ReliableOrdered); 80 | else 81 | netPeer.Send(writer,SendOptions.Sequenced); 82 | } 83 | 84 | public void DisconnectClient(params Client[] clients) 85 | { 86 | foreach(Client client in clients) 87 | { 88 | var netPeer = ClientToNetPeerMap[client]; 89 | server.DisconnectPeer(netPeer); 90 | } 91 | } 92 | 93 | public void Start(string ipaddress, int port) 94 | { 95 | listener = new EventBasedNetListener(); 96 | //Create a new server and only allow 32 connections 97 | server = new NetManager(listener, 32, "ConnectionKey"); 98 | server.UnsyncedEvents = true; 99 | server.Start(port); 100 | _LocalPort = server.LocalPort; 101 | 102 | listener.PeerDisconnectedEvent += (c,i) => 103 | { 104 | Client client = GetClientRecord(c); 105 | onDisconnectCallBack?.Invoke(client); 106 | }; 107 | 108 | listener.PeerConnectedEvent += c => 109 | { 110 | Client client = new Client(c.EndPoint.Host, c.EndPoint.Port); 111 | ClientToNetPeerMap.Add(client, c); 112 | onConnectCallBack?.Invoke(client); 113 | }; 114 | 115 | listener.NetworkReceiveEvent += (fromPeer, dataReader) => 116 | { 117 | Client client = GetClientRecord(fromPeer); 118 | var payload = dataReader.GetString(); 119 | ReceivedMessage receivedMessage = new ReceivedMessage(client, payload); 120 | onReceiveCallback.Invoke(receivedMessage); 121 | }; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Rhyno van der Sluijs 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 | -------------------------------------------------------------------------------- /LICENSE.LiteNetLib.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ruslan Pyrch 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. -------------------------------------------------------------------------------- /ObjectTransport.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport", "ObjectTransport\ObjectTransport.csproj", "{050C5519-2C8F-4F8D-BBB6-1D23439B372B}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{64660A3D-B48E-4CB7-BA05-125D15D19B26}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport.Test", "ObjectTransport.tests\ObjectTransport.Test.csproj", "{4AC2E216-9F30-4B10-AF9F-A620D50268D4}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Implementation", "Implementation", "{73435E1E-498B-4E04-B7BD-9B03B9E59839}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport.TCP", "Implementation\ObjectTransport.TCP\ObjectTransport.TCP.csproj", "{2C9790A6-D016-415C-B2AD-3F3AC0FFB53E}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport.UDP", "Implementation\ObjectTransport.UDP\ObjectTransport.UDP.csproj", "{4F86BC9F-6557-41AA-B831-927ED23E03D5}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport.JSON", "Implementation\ObjectTransport.Serializer.JSON\ObjectTransport.JSON.csproj", "{4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectTransport.Protobuf", "Implementation\ObjectTransport.Serializer.protobuf\ObjectTransport.Protobuf.csproj", "{515213C7-7358-4E13-B1B1-B60BA6C2EB21}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Messenger", "Demos\Messenger\Messenger.csproj", "{C9896DEA-3DDC-4F5B-B48E-2359DD01B951}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {050C5519-2C8F-4F8D-BBB6-1D23439B372B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {050C5519-2C8F-4F8D-BBB6-1D23439B372B}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {050C5519-2C8F-4F8D-BBB6-1D23439B372B}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {050C5519-2C8F-4F8D-BBB6-1D23439B372B}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {4AC2E216-9F30-4B10-AF9F-A620D50268D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {4AC2E216-9F30-4B10-AF9F-A620D50268D4}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {4AC2E216-9F30-4B10-AF9F-A620D50268D4}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {4AC2E216-9F30-4B10-AF9F-A620D50268D4}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {2C9790A6-D016-415C-B2AD-3F3AC0FFB53E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {2C9790A6-D016-415C-B2AD-3F3AC0FFB53E}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {2C9790A6-D016-415C-B2AD-3F3AC0FFB53E}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {2C9790A6-D016-415C-B2AD-3F3AC0FFB53E}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {4F86BC9F-6557-41AA-B831-927ED23E03D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {4F86BC9F-6557-41AA-B831-927ED23E03D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {4F86BC9F-6557-41AA-B831-927ED23E03D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {4F86BC9F-6557-41AA-B831-927ED23E03D5}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {515213C7-7358-4E13-B1B1-B60BA6C2EB21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {515213C7-7358-4E13-B1B1-B60BA6C2EB21}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {515213C7-7358-4E13-B1B1-B60BA6C2EB21}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {515213C7-7358-4E13-B1B1-B60BA6C2EB21}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {C9896DEA-3DDC-4F5B-B48E-2359DD01B951}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {C9896DEA-3DDC-4F5B-B48E-2359DD01B951}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {C9896DEA-3DDC-4F5B-B48E-2359DD01B951}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {C9896DEA-3DDC-4F5B-B48E-2359DD01B951}.Release|Any CPU.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(NestedProjects) = preSolution 63 | {2C9790A6-D016-415C-B2AD-3F3AC0FFB53E} = {73435E1E-498B-4E04-B7BD-9B03B9E59839} 64 | {4F86BC9F-6557-41AA-B831-927ED23E03D5} = {73435E1E-498B-4E04-B7BD-9B03B9E59839} 65 | {4E0C0A18-9DA4-4FAE-B11D-1C074DDC8CE0} = {73435E1E-498B-4E04-B7BD-9B03B9E59839} 66 | {515213C7-7358-4E13-B1B1-B60BA6C2EB21} = {73435E1E-498B-4E04-B7BD-9B03B9E59839} 67 | {C9896DEA-3DDC-4F5B-B48E-2359DD01B951} = {64660A3D-B48E-4CB7-BA05-125D15D19B26} 68 | EndGlobalSection 69 | GlobalSection(ExtensibilityGlobals) = postSolution 70 | SolutionGuid = {72829232-B072-42DE-A6EE-57F7557CFF03} 71 | EndGlobalSection 72 | EndGlobal 73 | -------------------------------------------------------------------------------- /ObjectTransport.tests/NetworkChannel.tests/INetworkChannelGenericTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using OTransport.Test.Utilities; 3 | using OTransport.tests; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using Test; 9 | 10 | namespace OTransport 11 | { 12 | [TestClass] 13 | public abstract class INetworkChannelGenericTests 14 | { 15 | protected INetworkChannel Client1 { get; set; } 16 | protected INetworkChannel Client2 { get; set; } 17 | protected INetworkChannel Server { get; set; } 18 | protected List ServerOnConnectClients { get; set; } 19 | protected List ServerOnDisconnectClients { get; set; } 20 | protected List Client1OnConnectClients { get; set; } 21 | protected List Client1OnDisconnectClients { get; set; } 22 | protected IObjectTransport Client1ObjectTransport { get; set; } 23 | protected IObjectTransport serverObjectTransport { get; set; } 24 | 25 | protected void SetUpNetworkChannels(INetworkChannel client,INetworkChannel client2,INetworkChannel server) 26 | { 27 | Client1 = client; 28 | Client2 = client2; 29 | Server = server; 30 | 31 | ServerOnConnectClients = new List(); 32 | ServerOnDisconnectClients = new List(); 33 | Client1OnConnectClients = new List(); 34 | Client1OnDisconnectClients = new List(); 35 | 36 | serverObjectTransport = TestObjectTransportFactory.CreateNewObjectTransport(Server); 37 | serverObjectTransport.OnClientConnect(c => ServerOnConnectClients.Add(c)); 38 | serverObjectTransport.OnClientDisconnect(c => ServerOnDisconnectClients.Add(c)); 39 | serverObjectTransport.Start("127.0.0.1", 0); 40 | 41 | Utilities.WaitFor(()=> server.LocalPort !=0); 42 | 43 | Client1ObjectTransport = TestObjectTransportFactory.CreateNewObjectTransport(Client1); 44 | Client1ObjectTransport.OnClientConnect(c => Client1OnConnectClients.Add(c)); 45 | Client1ObjectTransport.OnClientDisconnect(c => Client1OnDisconnectClients.Add(c)); 46 | Client1ObjectTransport.Start("127.0.0.1", Server.LocalPort); 47 | 48 | //Wait for the connection to have been made 49 | Utilities.WaitFor(()=> serverObjectTransport.GetConnectedClients().Count() == 1); 50 | Utilities.WaitFor(()=> Client1ObjectTransport.GetConnectedClients().Count() == 1); 51 | } 52 | [TestMethod] 53 | public void ClientDisconnects_CallbackCalled() 54 | { 55 | //Arrange 56 | Client client = null; 57 | Client clientDisconnect = null; 58 | 59 | client = Client1ObjectTransport.GetConnectedClients().First(); 60 | 61 | //Act 62 | serverObjectTransport.Stop(); 63 | 64 | Utilities.WaitFor(()=> Client1OnDisconnectClients.Count() > 0); 65 | clientDisconnect = Client1OnDisconnectClients.First(); 66 | 67 | //Assert 68 | Assert.AreEqual(client.IPAddress, "127.0.0.1"); 69 | Assert.AreEqual(clientDisconnect.IPAddress, "127.0.0.1"); 70 | Assert.AreEqual(clientDisconnect,client); 71 | Utilities.WaitFor(()=>Client1ObjectTransport.GetConnectedClients().Count() == 0); 72 | Utilities.WaitFor(()=>serverObjectTransport.GetConnectedClients().Count() == 0); 73 | } 74 | [TestMethod] 75 | public void Client_StartExecuted_ServerIsAddedAsClient() 76 | { 77 | //Arrange 78 | Client FirstClient = null; 79 | 80 | //Act 81 | FirstClient = Client1ObjectTransport.GetConnectedClients().First(); 82 | 83 | 84 | //Assert 85 | Assert.AreEqual(FirstClient.IPAddress, "127.0.0.1"); 86 | Assert.AreEqual(FirstClient.Port, Server.LocalPort); 87 | } 88 | 89 | [TestMethod] 90 | public void SendAndReplyMessage_ResponseIsCalled() 91 | { 92 | //Arrange 93 | Client client = null; 94 | client = Client1ObjectTransport.GetConnectedClients().First(); 95 | 96 | //Act 97 | serverObjectTransport.Receive() 98 | .Reply((o) => { return o; }) 99 | .Execute(); 100 | 101 | var mockObject = new MockObjectMessage() { Property1_string = "Mock Object" }; 102 | MockObjectMessage responseObject = null; 103 | 104 | Client1ObjectTransport.Send(mockObject) 105 | .Response((r) => {responseObject = r;}) 106 | .Execute(); 107 | 108 | Utilities.WaitFor(ref responseObject); 109 | 110 | //Assert 111 | Assert.AreEqual(responseObject.Property1_string, "Mock Object"); 112 | } 113 | 114 | [TestMethod] 115 | public void ClientDisconnectsServer_ServerOnClientDisconnectCalled() 116 | { 117 | //Arrange 118 | //Create a second client 119 | ObjectTransport clientObjectTransport2 = TestObjectTransportFactory.CreateNewObjectTransport(Client2); 120 | clientObjectTransport2.Start("127.0.0.1", Server.LocalPort); 121 | 122 | //Wait for the connection to have been made 123 | Utilities.WaitFor(() => serverObjectTransport.GetConnectedClients().Count() == 2); 124 | 125 | //Act 126 | 127 | //disconnect the server from the client 128 | Client1ObjectTransport.DisconnectClient(); 129 | 130 | Utilities.WaitFor(()=> ServerOnDisconnectClients.Count ==1); 131 | 132 | //Assert 133 | //Ensure that the client record was disconnect from the server 134 | Assert.AreEqual(1,serverObjectTransport.GetConnectedClients().Count()); 135 | 136 | //Esnure that the client who disconnected from the server was the one that we called disconect 137 | Assert.AreEqual(ServerOnDisconnectClients.First().Port, Client1.LocalPort); 138 | } 139 | 140 | [TestMethod] 141 | public void Server_ClientDisconnects_CallbackCalled() 142 | { 143 | //Arrange 144 | 145 | //Act 146 | 147 | Client1ObjectTransport.Stop(); 148 | Utilities.WaitFor(()=> ServerOnDisconnectClients.Count() == 1); 149 | 150 | //Assert 151 | var clientConnect = ServerOnConnectClients.First(); 152 | var clientDisconnect = ServerOnDisconnectClients.First(); 153 | Assert.AreEqual(clientConnect.IPAddress, "127.0.0.1"); 154 | Assert.AreEqual(clientDisconnect.IPAddress, "127.0.0.1"); 155 | Assert.AreEqual(clientDisconnect,clientConnect); 156 | Assert.AreEqual(0,Client1ObjectTransport.GetConnectedClients().Count()); 157 | Assert.AreEqual(0,serverObjectTransport.GetConnectedClients().Count()); 158 | } 159 | 160 | [TestMethod] 161 | public void ServerWith2Clients_ServerDisconnects1Client_1ClientDisconnected() 162 | { 163 | //Arrange 164 | ObjectTransport clientObjectTransport2 = TestObjectTransportFactory.CreateNewObjectTransport(Client2); 165 | clientObjectTransport2.Start("127.0.0.1", Server.LocalPort); 166 | 167 | //Wait for the connection to have been made 168 | Utilities.WaitFor(() => serverObjectTransport.GetConnectedClients().Count() == 2); 169 | var FirstClient = serverObjectTransport.GetConnectedClients().First(); 170 | 171 | //Act 172 | 173 | serverObjectTransport.DisconnectClient(FirstClient); 174 | Utilities.WaitFor(()=> ServerOnDisconnectClients.Count() ==1); 175 | 176 | //Assert 177 | 178 | Client LastClient = serverObjectTransport.GetConnectedClients().First(); 179 | Assert.AreEqual(1, serverObjectTransport.GetConnectedClients().Count()); 180 | Assert.AreNotEqual(FirstClient.Port, LastClient.Port); 181 | } 182 | [TestMethod] 183 | public void ServerWith2Clients_ServerDisconnects2Client_AllClientsDisconnected() 184 | { 185 | //Arrange 186 | 187 | //Create a second client 188 | ObjectTransport clientObjectTransport2 = TestObjectTransportFactory.CreateNewObjectTransport(Client2); 189 | clientObjectTransport2.Start("127.0.0.1", Server.LocalPort); 190 | 191 | //Wait for the connection to have been made 192 | Utilities.WaitFor(() => serverObjectTransport.GetConnectedClients().Count() == 2); 193 | 194 | //Act 195 | 196 | var allClients = serverObjectTransport.GetConnectedClients().ToArray(); 197 | serverObjectTransport.DisconnectClient(allClients); 198 | 199 | Utilities.WaitFor(() => ServerOnDisconnectClients.Count == 2); 200 | 201 | //Assert 202 | Assert.AreEqual(0, serverObjectTransport.GetConnectedClients().Count()); 203 | Assert.AreEqual(2, ServerOnDisconnectClients.Count()); 204 | } 205 | 206 | [TestMethod] 207 | public void Server_ReceivesObjects_CorrectObjectReceived() 208 | { 209 | //Arrange 210 | MockObjectMessage receivedObject = null; 211 | 212 | //Act 213 | serverObjectTransport.Receive(o => 214 | { 215 | receivedObject = o; 216 | 217 | }).Execute(); 218 | 219 | Client1ObjectTransport.Send(new MockObjectMessage() 220 | { 221 | Property1_string = "hello world!", 222 | Property2_int = 123, 223 | Property3_decimal = 12.3M 224 | }).Execute(); 225 | 226 | Utilities.WaitFor(ref receivedObject); 227 | 228 | //Assert 229 | Assert.AreEqual("hello world!", receivedObject.Property1_string); 230 | Assert.AreEqual(123, receivedObject.Property2_int); 231 | Assert.AreEqual(12.3M, receivedObject.Property3_decimal); 232 | } 233 | 234 | [TestMethod] 235 | public void Server_SendObject_CorrectObjectSent() 236 | { 237 | //Arrange 238 | MockObjectMessage receivedObject = null; 239 | 240 | Client client = serverObjectTransport.GetConnectedClients().First(); 241 | 242 | //Act 243 | Client1ObjectTransport.Receive(o => 244 | receivedObject = o 245 | ).Execute(); 246 | 247 | serverObjectTransport.Send(new MockObjectMessage() 248 | { 249 | Property1_string = "hello world!", 250 | Property2_int = 123, 251 | Property3_decimal = 12.3M 252 | 253 | }) 254 | .To(client) 255 | .Execute(); 256 | 257 | Utilities.WaitFor(ref receivedObject); 258 | 259 | //Assert 260 | Assert.AreEqual("hello world!", receivedObject.Property1_string); 261 | Assert.AreEqual(123, receivedObject.Property2_int); 262 | Assert.AreEqual(12.3M, receivedObject.Property3_decimal); 263 | } 264 | 265 | 266 | [TestMethod] 267 | public void Server_WhenClientConnects_CallbackFunctionCalled() 268 | { 269 | Assert.AreEqual(serverObjectTransport.GetConnectedClients().Count(), 1); 270 | } 271 | 272 | [TestMethod] 273 | public void Server_ServerDisconnects2Client_AllClientsDisconnected() 274 | { 275 | //Arrange 276 | 277 | //Create a second client 278 | ObjectTransport clientObjectTransport2 = TestObjectTransportFactory.CreateNewObjectTransport(Client2); 279 | clientObjectTransport2.Start("127.0.0.1", Server.LocalPort); 280 | 281 | //Wait for the connection to have been made 282 | Utilities.WaitFor(() => serverObjectTransport.GetConnectedClients().Count() == 2); 283 | 284 | //Act 285 | 286 | var allClients = serverObjectTransport.GetConnectedClients().ToArray(); 287 | serverObjectTransport.DisconnectClient(allClients); 288 | 289 | Utilities.WaitFor(() => ServerOnDisconnectClients.Count == 2); 290 | 291 | //Assert 292 | Assert.AreEqual(0, serverObjectTransport.GetConnectedClients().Count()); 293 | Assert.AreEqual(2, ServerOnDisconnectClients.Count()); 294 | } 295 | 296 | [TestMethod] 297 | [Ignore] 298 | public void Send_TwoObjectsStraightAway_BothProcessedSeperatly() 299 | { 300 | //Arrange 301 | Client client = null; 302 | client = Client1ObjectTransport.GetConnectedClients().First(); 303 | 304 | //Act 305 | serverObjectTransport.Receive() 306 | .Reply((o) => { return o; }) 307 | .Execute(); 308 | 309 | var mockObject = new MockObjectMessage() { Property1_string = "Mock Object" }; 310 | MockObjectMessage responseObject = null; 311 | MockObjectMessage responseObject2 = null; 312 | 313 | Client1ObjectTransport.Send(mockObject) 314 | .Response((r) => {responseObject = r;}) 315 | .Execute(); 316 | 317 | Client1ObjectTransport.Send(mockObject) 318 | .Response((r) => {responseObject2 = r;}) 319 | .Execute(); 320 | 321 | Utilities.WaitFor(ref responseObject); 322 | Utilities.WaitFor(ref responseObject2); 323 | 324 | //Assert 325 | Assert.AreEqual(responseObject.Property1_string, "Mock Object"); 326 | Assert.AreEqual(responseObject2.Property1_string, "Mock Object"); 327 | } 328 | 329 | [TestCleanup] 330 | public void ShutDownNetworkChannels() 331 | { 332 | Server.Stop(); 333 | Client1.Stop(); 334 | Client2.Stop(); 335 | } 336 | 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /ObjectTransport.tests/NetworkChannel.tests/TCPNetworkChannelGenericTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using OTransport; 3 | using OTransport.NetworkChannel.TCP; 4 | using OTransport.Test.Utilities; 5 | using OTransport.tests; 6 | using System; 7 | using System.Linq; 8 | using Test; 9 | 10 | namespace OTranport 11 | { 12 | [TestClass] 13 | public class TCPNetworkChannelGenericTests : INetworkChannelGenericTests 14 | { 15 | [TestInitialize] 16 | public void SetUpNetworkChannels() 17 | { 18 | SetUpNetworkChannels(new TCPClientChannel(), new TCPClientChannel(), new TCPServerChannel()); 19 | } 20 | [TestMethod] 21 | [ExpectedException(typeof(NotSupportedException))] 22 | public void TCPClient_SendUnreliably_ExceptionThrown() 23 | { 24 | //Arrange 25 | Client client = null; 26 | Client clientDisconnect = null; 27 | 28 | ObjectTransport serverObjectTransport = TestObjectTransportFactory.CreateNewObjectTransport(Server); 29 | serverObjectTransport.Start("127.0.0.1", 0); 30 | 31 | ObjectTransport clientObjectTransport = TestObjectTransportFactory.CreateNewObjectTransport(Client1); 32 | clientObjectTransport.OnClientDisconnect(c => clientDisconnect = c); 33 | clientObjectTransport.Start("127.0.0.1", Server.LocalPort); 34 | 35 | Utilities.WaitFor(() => serverObjectTransport.GetConnectedClients().Count() == 1); 36 | 37 | client = clientObjectTransport.GetConnectedClients().First(); 38 | Utilities.WaitFor(ref client); 39 | 40 | var message = new MockObjectMessage(); 41 | //Act 42 | 43 | clientObjectTransport.Send(message) 44 | .Unreliable() 45 | .Execute(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ObjectTransport.tests/NetworkChannel.tests/UDPNetworkChannelGenericTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using OTransport; 3 | using OTransport.NetworkChannel.TCP; 4 | using OTransport.NetworkChannel.UDP; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace OTranport 10 | { 11 | [TestClass] 12 | public class UDPNetworkChannelGenericTests : INetworkChannelGenericTests 13 | { 14 | [TestInitialize] 15 | public void SetUpNetworkChannels() 16 | { 17 | SetUpNetworkChannels(new UDPClientChannel(), new UDPClientChannel(), new UDPServerChannel()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ObjectTransport.tests/NetworkChannel.tests/Utilities/TCPNetworkChannelFactory.cs: -------------------------------------------------------------------------------- 1 | using OTransport.NetworkChannel.TCP; 2 | using OTransport; 3 | using OTransport.Test.Utilities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Threading; 8 | 9 | namespace Test 10 | { 11 | class TCPObjectTransportChannel 12 | { 13 | private static TCPServerChannel server = new TCPServerChannel(); 14 | private static TCPClientChannel tcpclient = new TCPClientChannel(); 15 | public static Tuple GetConnectObjectTransports() 16 | { 17 | server.Start("127.0.0.1", 0); 18 | 19 | ObjectTransport serverObjectTransport = TestObjectTransportFactory.CreateNewObjectTransport(server); 20 | 21 | tcpclient.Start("127.0.0.1", server.LocalPort); 22 | ObjectTransport client = TestObjectTransportFactory.CreateNewObjectTransport(tcpclient); 23 | 24 | Tuple result = new Tuple(serverObjectTransport, client); 25 | return result; 26 | } 27 | public static void TearDown() 28 | { 29 | if (server != null) 30 | server.Stop(); 31 | if (tcpclient != null) 32 | tcpclient.Stop(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ObjectTransport.tests/ObjectTransport.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp1.1 5 | 6 | false 7 | 8 | ObjectTransport.Test 9 | 10 | ObjectTransport.Test 11 | PackageReference 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ObjectTransport.tests/ObjectTransport_OnConnect.tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using OTransport.Test.Utilities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Test; 7 | 8 | namespace OTransport.tests 9 | { 10 | [TestClass] 11 | public class ObjectTransport_OnConnect 12 | { 13 | [TestMethod] 14 | public void OnClientConnect_ClientConnectsToObject_ClientInjectedIntoAction() 15 | { 16 | //Arrange 17 | var sentJson = string.Empty; 18 | var client = new Client("10.0.0.1",123); 19 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 20 | 21 | Client connectedClient = null; 22 | 23 | //Act 24 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 25 | transport.OnClientConnect(c => 26 | { 27 | connectedClient = c; 28 | }); 29 | 30 | networkChannel.SimulateClientConnect(client); 31 | //Assert 32 | Assert.AreEqual(client, connectedClient); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ObjectTransport.tests/ObjectTransport_Receive.tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Text.RegularExpressions; 4 | using Test; 5 | using System.Text; 6 | using OTransport.Test.Utilities; 7 | 8 | namespace OTransport.tests 9 | { 10 | [TestClass] 11 | public class ObjectTransport_Receive 12 | { 13 | 14 | [TestMethod] 15 | public void Receive_ObjectType_ObjectReceiveFunctionExecuted() 16 | { 17 | //Arrange 18 | 19 | Client client = new Client("10.0.0.1",123); 20 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 21 | 22 | MockObjectMessage receive = new MockObjectMessage(); 23 | 24 | //Act 25 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 26 | transport.Receive(o => 27 | { 28 | receive = o; 29 | } 30 | ) 31 | .Execute(); 32 | 33 | networkChannel.SimulateClientConnect(client); 34 | networkChannel.SimulateClientResponse(client, 35 | "OTransport.tests.MockObjectMessage, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null::{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}" 36 | ); 37 | //Assert 38 | Assert.AreEqual("Test String", receive.Property1_string); 39 | Assert.AreEqual(12, receive.Property2_int); 40 | Assert.AreEqual(1.33M, receive.Property3_decimal); 41 | } 42 | [TestMethod] 43 | public void Receive_InvalidObjectType_ObjectNotProcessed() 44 | { 45 | //Arrange 46 | 47 | Client client = new Client("10.0.0.1", 123); 48 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 49 | 50 | MockObjectMessage receive = new MockObjectMessage(); 51 | 52 | //Act 53 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 54 | transport.Receive(o => 55 | { 56 | receive = o; 57 | } 58 | ) 59 | .Execute(); 60 | 61 | networkChannel.SimulateClientConnect(client); 62 | networkChannel.SimulateClientResponse(client, "OTransport.tests.NOTHING, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null::{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}"); 63 | } 64 | 65 | [TestMethod] 66 | public void Receive_InvalidPayload_PayloadNotProcessed() 67 | { 68 | //Arrange 69 | 70 | Client client = new Client("10.0.0.1",123); 71 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 72 | 73 | MockObjectMessage receive = null; 74 | 75 | //Act 76 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 77 | transport.Receive(o => 78 | { 79 | receive = o; 80 | } 81 | ) 82 | .Execute(); 83 | 84 | networkChannel.SimulateClientConnect(client); 85 | networkChannel.SimulateClientResponse(client, 86 | "{\"Type\":\"OTransport.tests.MockObjectMessage, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\",:{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}}" 87 | ); 88 | 89 | //Assert 90 | Assert.IsNull(receive); 91 | } 92 | 93 | [TestMethod] 94 | [ExpectedException(typeof(ObjectTransportException))] 95 | public void Receve_RegisterSameTypeTwice_ObjectTransportExceptionThrown() 96 | { 97 | //Arrange 98 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 99 | 100 | //Act 101 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 102 | transport.Receive().Execute(); 103 | transport.Receive().Execute(); 104 | } 105 | 106 | [TestMethod] 107 | public void Receive_ReplyToReceivedObject_ObjectIsSentBack() 108 | { 109 | //Arrange 110 | string replayPayload = null; 111 | Client client = new Client("10.0.0.1",123); 112 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 113 | .OnSendHandle((Client, payload) => replayPayload = payload); 114 | 115 | 116 | //Act 117 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 118 | transport.Receive() 119 | .Reply(o=> 120 | { 121 | MockObjectMessage sendBack = new MockObjectMessage(); 122 | sendBack.Property1_string = "Reply message"; 123 | sendBack.Property2_int = 12; 124 | sendBack.Property3_decimal = 1.33M; 125 | 126 | return sendBack; 127 | 128 | }) 129 | .Execute(); 130 | 131 | 132 | networkChannel.SimulateClientConnect(client); 133 | networkChannel.SimulateClientResponse(client, 134 | "OTransport.tests.MockObjectMessage, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null::{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}" 135 | ); 136 | 137 | //Assert 138 | Assert.AreEqual( "OTransport.tests.MockObjectMessage, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null::{\"Property1_string\":\"Reply message\",\"Property2_int\":12,\"Property3_decimal\":1.33}" , replayPayload); 139 | } 140 | 141 | [TestMethod] 142 | public void SendReceiveThroughChannel_ObjectTransportConnectedChannel_ObjectSentAndReceivedBetweenClients() 143 | { 144 | //Arrange 145 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 146 | 147 | MockObjectMessage sendMessage = new MockObjectMessage(); 148 | sendMessage.Property1_string = "test send"; 149 | sendMessage.Property2_int = 123; 150 | sendMessage.Property3_decimal = 56M; 151 | 152 | MockObjectMessage receivedMessage = null; 153 | 154 | //Act 155 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1); 156 | client1.Receive(o=> 157 | { 158 | receivedMessage = o; 159 | }) 160 | .Execute(); 161 | 162 | 163 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2); 164 | client2.Send(sendMessage) 165 | .Execute(); 166 | 167 | Utilities.WaitFor(ref receivedMessage); 168 | 169 | //Assert 170 | Assert.AreEqual(sendMessage.Property3_decimal, receivedMessage.Property3_decimal); 171 | Assert.AreEqual(sendMessage.Property1_string, receivedMessage.Property1_string); 172 | Assert.AreEqual(sendMessage.Property2_int, receivedMessage.Property2_int); 173 | } 174 | 175 | [TestMethod] 176 | public void Receive_WithClientAction_ObjectAndClientInjectedInAction() 177 | { 178 | //Arrange 179 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 180 | 181 | MockObjectMessage sendMessage = new MockObjectMessage(); 182 | sendMessage.Property1_string = "test send"; 183 | sendMessage.Property2_int = 123; 184 | sendMessage.Property3_decimal = 56M; 185 | 186 | MockObjectMessage receivedMessage = null; 187 | Client receivedClient = null; 188 | 189 | //Act 190 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1); 191 | client1.Receive((c,o)=> 192 | { 193 | receivedClient = c; 194 | receivedMessage = o; 195 | }) 196 | .Execute(); 197 | 198 | 199 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2); 200 | client2.Send(sendMessage) 201 | .Execute(); 202 | 203 | //Assert 204 | Assert.AreEqual(sendMessage.Property3_decimal, receivedMessage.Property3_decimal); 205 | Assert.AreEqual(sendMessage.Property1_string, receivedMessage.Property1_string); 206 | Assert.AreEqual(sendMessage.Property2_int, receivedMessage.Property2_int); 207 | Assert.AreEqual("10.0.0.2", receivedClient.IPAddress); 208 | } 209 | 210 | [TestMethod] 211 | public void ReceiveReply_WithClientAction_ObjectAndClientInjectedInToAction() 212 | { 213 | //Arrange 214 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 215 | 216 | MockObjectMessage sendMessage = new MockObjectMessage(); 217 | sendMessage.Property1_string = "test send"; 218 | sendMessage.Property2_int = 123; 219 | sendMessage.Property3_decimal = 56M; 220 | 221 | MockObjectMessage receivedMessage = null; 222 | Client receivedClient = null; 223 | 224 | //Act 225 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1); 226 | client1.Receive() 227 | .Reply((c,o) => 228 | { 229 | receivedMessage = o; 230 | receivedClient = c; 231 | return null; 232 | }) 233 | .Execute(); 234 | 235 | 236 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2); 237 | client2.Send(sendMessage) 238 | .Execute(); 239 | 240 | Utilities.WaitFor(ref receivedMessage); 241 | 242 | //Assert 243 | Assert.AreEqual(sendMessage.Property3_decimal, receivedMessage.Property3_decimal); 244 | Assert.AreEqual(sendMessage.Property1_string, receivedMessage.Property1_string); 245 | Assert.AreEqual(sendMessage.Property2_int, receivedMessage.Property2_int); 246 | Assert.AreEqual("10.0.0.2", receivedClient.IPAddress); 247 | } 248 | 249 | [TestMethod] 250 | public void SendReceiveReplyThroughChannel_TwoObjectTransportsConnected_SameTokenUsed() 251 | { 252 | //Arrange 253 | var client2ReceiveFunctionCalled = false; 254 | var client2RespondFunctionCalled = false; 255 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 256 | 257 | MockObjectMessage sendMessage = new MockObjectMessage(); 258 | sendMessage.Property1_string = "test send"; 259 | sendMessage.Property2_int = 123; 260 | sendMessage.Property3_decimal = 56M; 261 | 262 | MockObjectMessage receivedMessage = null; 263 | 264 | //Act 265 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1); 266 | client1.Receive() 267 | .Reply((c,o) => 268 | { 269 | o.Property1_string = "replied"; 270 | return o; 271 | }) 272 | .Execute(); 273 | 274 | 275 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2); 276 | client2.Send(sendMessage) 277 | .Response(o => 278 | { 279 | client2RespondFunctionCalled = true; 280 | receivedMessage = o; 281 | }) 282 | .Execute(); 283 | 284 | client2.Receive(o => 285 | { 286 | client2ReceiveFunctionCalled = true; 287 | receivedMessage = o; 288 | }).Execute(); 289 | 290 | Utilities.WaitFor(ref receivedMessage); 291 | 292 | //Assert 293 | Assert.IsFalse(client2ReceiveFunctionCalled); 294 | Assert.IsTrue(client2RespondFunctionCalled); 295 | } 296 | [TestMethod] 297 | public void Receive_ObjectWithBinaryProperty_BinaryReceived() 298 | { 299 | //Arrange 300 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 301 | 302 | MockObjectMessageWithBinary sendMessage = new MockObjectMessageWithBinary(); 303 | sendMessage.Property2_String = "Message with binary"; 304 | sendMessage.Property1_Bytes = Encoding.ASCII.GetBytes("hello world"); 305 | 306 | MockObjectMessageWithBinary receivedMessage = null; 307 | Client receivedClient = null; 308 | 309 | //Act 310 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1); 311 | client1.Receive((c, o) => 312 | { 313 | receivedClient = c; 314 | receivedMessage = o; 315 | }) 316 | .Execute(); 317 | 318 | 319 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2); 320 | client2.Send(sendMessage) 321 | .Execute(); 322 | 323 | //Assert 324 | Assert.AreEqual("hello world", System.Text.Encoding.UTF8.GetString(receivedMessage.Property1_Bytes)); 325 | Assert.AreEqual(receivedMessage.Property2_String, "Message with binary"); 326 | Assert.AreEqual("10.0.0.2", receivedClient.IPAddress); 327 | } 328 | 329 | [TestMethod] 330 | public void OnFailedReceived_InvalidPayloadReceived_OnFailHandleExecuted() 331 | { 332 | //Arrange 333 | 334 | Client client = new Client("10.0.0.1", 123); 335 | ReceivedMessage receivedMessage = null; 336 | Exception failedException = null; 337 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel(); 338 | 339 | MockObjectMessage receive = new MockObjectMessage(); 340 | 341 | //Act 342 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 343 | transport.Receive(o => 344 | { 345 | receive = o; 346 | } 347 | ) 348 | .Execute(); 349 | 350 | transport.OnFailedReceive((r, e) => 351 | { 352 | receivedMessage = r; 353 | failedException = e; 354 | }); 355 | 356 | networkChannel.SimulateClientConnect(client); 357 | networkChannel.SimulateClientResponse(client, "OTransport.tests.NOTHING, ObjectTransport.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nullProperty1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}"); 358 | 359 | Assert.IsNotNull(receivedMessage); 360 | Assert.IsNotNull(failedException); 361 | } 362 | 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /ObjectTransport.tests/ObjectTransport_Send.tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Text.RegularExpressions; 4 | using Test; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using OTransport.Test.Utilities; 8 | 9 | namespace OTransport.tests 10 | { 11 | [TestClass] 12 | public class ObjectTransport_Send 13 | { 14 | [TestMethod] 15 | public void SendExecute_ObjectWithProperties_PayloadWithObjectAndTypeSent() 16 | { 17 | //Arrange 18 | var sentPayload = string.Empty; 19 | var client = new Client("10.0.0.1",123); 20 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 21 | .OnSendHandle((Client, payload) => sentPayload = payload); 22 | 23 | MockObjectMessage sendObject = new MockObjectMessage(); 24 | sendObject.Property1_string = "Test String"; 25 | sendObject.Property2_int = 12; 26 | sendObject.Property3_decimal = 1.33M; 27 | 28 | //Act 29 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 30 | networkChannel.SimulateClientConnect(client); 31 | transport.Send(sendObject) 32 | .To(client) 33 | .Execute(); 34 | 35 | //Assert 36 | Assert.AreEqual(typeof(MockObjectMessage).AssemblyQualifiedName + "::{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}", sentPayload); 37 | } 38 | [TestMethod] 39 | public void SendWithResponse_ObjectWithPropertiesSet_PayloadWithObjectAndTokenSent() 40 | { 41 | //Arrange 42 | var sentPayload = string.Empty; 43 | var client = new Client("10.0.0.1",123); 44 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 45 | .OnSendHandle((Client, payload) => sentPayload = payload); 46 | 47 | MockObjectMessage sendObject = new MockObjectMessage(); 48 | sendObject.Property1_string = "Test String"; 49 | sendObject.Property2_int = 12; 50 | sendObject.Property3_decimal = 1.33M; 51 | 52 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 53 | networkChannel.SimulateClientConnect(client); 54 | 55 | //Act 56 | 57 | transport.Send(sendObject) 58 | .Response(o => o.GetType()) 59 | .Execute(); 60 | 61 | 62 | Utilities.WaitFor(ref sentPayload); 63 | 64 | //Assert 65 | Regex rgx = new Regex(typeof(MockObjectMessage).AssemblyQualifiedName + "::(.*)::{\"Property1_string\":\"Test String\",\"Property2_int\":12,\"Property3_decimal\":1.33}"); 66 | Assert.IsTrue(rgx.IsMatch(sentPayload)); 67 | } 68 | 69 | [TestMethod] 70 | public void SendToAll_AllClients_AllClientsAreSendTo() 71 | { 72 | //Arrange 73 | var client1 = new Client("10.0.0.1", 123); 74 | var client2 = new Client("10.0.0.2", 123); 75 | var client3 = new Client("10.0.0.3", 123); 76 | 77 | var clientsSendTo = new List(); 78 | 79 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 80 | .OnSendHandle((Client, payload) => clientsSendTo.Add(Client)); 81 | 82 | MockObjectMessage sendObject = new MockObjectMessage(); 83 | sendObject.Property1_string = "Test String"; 84 | sendObject.Property2_int = 12; 85 | sendObject.Property3_decimal = 1.33M; 86 | 87 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 88 | 89 | networkChannel.SimulateClientConnect(client1); 90 | networkChannel.SimulateClientConnect(client2); 91 | networkChannel.SimulateClientConnect(client3); 92 | 93 | //Act 94 | 95 | transport.Send(sendObject) 96 | .Response(o => o.GetType()) 97 | .ToAll() 98 | .Execute(); 99 | 100 | //Assert 101 | Assert.AreEqual(3, clientsSendTo.Count); 102 | Assert.AreEqual(clientsSendTo[0].IPAddress, "10.0.0.1"); 103 | Assert.AreEqual(clientsSendTo[1].IPAddress, "10.0.0.2"); 104 | Assert.AreEqual(clientsSendTo[2].IPAddress, "10.0.0.3"); 105 | 106 | } 107 | 108 | [TestMethod] 109 | public void SendToAll_Except1Client_AllClientsExcept1AreSendTo() 110 | { 111 | //Arrange 112 | var client1 = new Client("10.0.0.1", 123); 113 | var client2 = new Client("10.0.0.2", 123); 114 | var client3 = new Client("10.0.0.3", 123); 115 | 116 | var clientsSendTo = new List(); 117 | 118 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 119 | .OnSendHandle((Client, paylaod) => clientsSendTo.Add(Client)); 120 | 121 | MockObjectMessage sendObject = new MockObjectMessage(); 122 | sendObject.Property1_string = "Test String"; 123 | sendObject.Property2_int = 12; 124 | sendObject.Property3_decimal = 1.33M; 125 | 126 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 127 | 128 | networkChannel.SimulateClientConnect(client1); 129 | networkChannel.SimulateClientConnect(client2); 130 | networkChannel.SimulateClientConnect(client3); 131 | 132 | //Act 133 | 134 | transport.Send(sendObject) 135 | .Response(o => o.GetType()) 136 | .ToAllExcept(client1) 137 | .Execute(); 138 | 139 | //Assert 140 | Assert.AreEqual(2, clientsSendTo.Count); 141 | Assert.AreEqual(clientsSendTo[0].IPAddress, "10.0.0.2"); 142 | Assert.AreEqual(clientsSendTo[1].IPAddress, "10.0.0.3"); 143 | 144 | } 145 | 146 | [TestMethod] 147 | public void SendToAll_Except2Client_AllClientsExcept2AreSendTo() 148 | { 149 | //Arrange 150 | var client1 = new Client("10.0.0.1", 123); 151 | var client2 = new Client("10.0.0.2", 123); 152 | var client3 = new Client("10.0.0.3", 123); 153 | 154 | var clientsSendTo = new List(); 155 | 156 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 157 | .OnSendHandle((Client, paylaod) => clientsSendTo.Add(Client)); 158 | 159 | MockObjectMessage sendObject = new MockObjectMessage(); 160 | sendObject.Property1_string = "Test String"; 161 | sendObject.Property2_int = 12; 162 | sendObject.Property3_decimal = 1.33M; 163 | 164 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 165 | 166 | networkChannel.SimulateClientConnect(client1); 167 | networkChannel.SimulateClientConnect(client2); 168 | networkChannel.SimulateClientConnect(client3); 169 | 170 | //Act 171 | 172 | transport.Send(sendObject) 173 | .Response(o => o.GetType()) 174 | .ToAllExcept(client1,client3) 175 | .Execute(); 176 | 177 | //Assert 178 | Assert.AreEqual(1, clientsSendTo.Count); 179 | Assert.AreEqual(clientsSendTo[0].IPAddress, "10.0.0.2"); 180 | 181 | } 182 | 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /ObjectTransport.tests/ObjectTransport_TimeOut.tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Text.RegularExpressions; 4 | using Test; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Linq; 8 | using OTransport.Test.Utilities; 9 | 10 | namespace OTransport.tests 11 | { 12 | [TestClass] 13 | public class ObjectTransport_TimeOut 14 | { 15 | [TestMethod] 16 | public void TimeOut_TimeOutFunctionSet_TimeOutFunctionCalled() 17 | { 18 | //Arrange 19 | var client = new Client("10.0.0.1",123); 20 | Client[] clientsWhoDidNotRespond = null; 21 | MockObjectMessage messageThatTimedOut = null; 22 | 23 | var sentPayload = string.Empty; 24 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 25 | .OnSendHandle((Client, payload) => sentPayload = payload); 26 | 27 | MockObjectMessage sendObject = new MockObjectMessage(); 28 | sendObject.Property1_string = "Test String"; 29 | sendObject.Property2_int = 12; 30 | sendObject.Property3_decimal = 1.33M; 31 | 32 | //Act 33 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 34 | networkChannel.SimulateClientConnect(client); 35 | 36 | transport.Send(sendObject) 37 | .Response(o => { }) 38 | .SetTimeOut(1) 39 | .OnTimeOut( 40 | (c,o)=> { 41 | clientsWhoDidNotRespond = c; 42 | messageThatTimedOut = o; 43 | }) 44 | .Execute(); 45 | 46 | Utilities.WaitFor(ref clientsWhoDidNotRespond); 47 | 48 | //Assert 49 | Assert.AreEqual(1,clientsWhoDidNotRespond.Length); 50 | Assert.AreEqual(sendObject,messageThatTimedOut); 51 | } 52 | 53 | [TestMethod] 54 | public void TimeOut_MessageSentToMultipleClientsWithSomeResponding_TimeOutFunctionReturnsClientsWhoDidNotRespond() 55 | { 56 | //Arrange 57 | var client1 = new Client("10.0.0.1",123); 58 | var client2 = new Client("10.0.0.2",123); 59 | var client3 = new Client("10.0.0.3",123); 60 | 61 | Client[] clientsWhoDidNotRespond = null; 62 | MockObjectMessage messageThatTimedOut = null; 63 | 64 | var sentPayload = string.Empty; 65 | var networkChannel = MockNetworkChannelFactory.GetMockedNetworkChannel() 66 | .OnSendHandle((Client, payload) => sentPayload = payload); 67 | 68 | MockObjectMessage sendObject = new MockObjectMessage(); 69 | sendObject.Property1_string = "Test String"; 70 | sendObject.Property2_int = 12; 71 | sendObject.Property3_decimal = 1.33M; 72 | 73 | ObjectTransport transport = TestObjectTransportFactory.CreateNewObjectTransport(networkChannel); 74 | networkChannel.SimulateClientConnect(client1); 75 | networkChannel.SimulateClientConnect(client2); 76 | networkChannel.SimulateClientConnect(client3); 77 | 78 | //Act 79 | transport.Send(sendObject) 80 | .Response(o => { }) 81 | .SetTimeOut(2) 82 | .OnTimeOut( 83 | (c,o)=> { 84 | clientsWhoDidNotRespond = c; 85 | messageThatTimedOut = o; 86 | }) 87 | .ToAll() 88 | .Execute(); 89 | 90 | //Echo back the message 91 | networkChannel.SimulateClientResponse(client2, sentPayload); 92 | 93 | Utilities.WaitFor(ref messageThatTimedOut); 94 | 95 | //Assert 96 | Assert.AreEqual(2,clientsWhoDidNotRespond.Length); 97 | Assert.IsTrue(clientsWhoDidNotRespond.Contains(client1)); 98 | Assert.IsTrue(clientsWhoDidNotRespond.Contains(client3)); 99 | Assert.AreEqual(sendObject,messageThatTimedOut); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Serializer/Protobuf_MockObjectMessage.cs: -------------------------------------------------------------------------------- 1 | using ProtoBuf; 2 | 3 | namespace OTransport.tests 4 | { 5 | [ProtoContract] 6 | public class Protobuf_MockObjectMessage 7 | { 8 | [ProtoMember(1)] 9 | public string Property1_string { get; set; } 10 | [ProtoMember(2)] 11 | public int Property2_int { get; set; } 12 | [ProtoMember(3)] 13 | public decimal Property3_decimal { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Serializer/Protobuf_Serializer.tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using OTransport; 3 | using OTransport.Serializer.protobuf; 4 | using OTransport.Test.Utilities; 5 | using OTransport.tests; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | using Test; 10 | 11 | namespace OTransport.Test.Serializer 12 | { 13 | [TestClass] 14 | public class Protobuf_Serializer 15 | { 16 | [TestMethod] 17 | public void Protobuff_UsingProtobuffSerializer_objectIsSentAndReceived() 18 | { 19 | //Arrange 20 | var joinedNetworkChannels = MockNetworkChannelFactory.GetConnectedChannels(); 21 | 22 | Protobuf_MockObjectMessage sendMessage = new Protobuf_MockObjectMessage(); 23 | sendMessage.Property1_string = "test send"; 24 | sendMessage.Property2_int = 123; 25 | sendMessage.Property3_decimal = 56M; 26 | 27 | Protobuf_MockObjectMessage receivedMessage = null; 28 | Client receivedClient = null; 29 | 30 | //Act 31 | ObjectTransport client1 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item1,new ProtobufSerializer()); 32 | client1.Receive((c, o) => 33 | { 34 | receivedClient = c; 35 | receivedMessage = o; 36 | }) 37 | .Execute(); 38 | 39 | 40 | ObjectTransport client2 = TestObjectTransportFactory.CreateNewObjectTransport(joinedNetworkChannels.Item2,new ProtobufSerializer()); 41 | client2.Send(sendMessage) 42 | .Execute(); 43 | 44 | //Assert 45 | Assert.AreEqual(sendMessage.Property3_decimal, receivedMessage.Property3_decimal); 46 | Assert.AreEqual(sendMessage.Property1_string, receivedMessage.Property1_string); 47 | Assert.AreEqual(sendMessage.Property2_int, receivedMessage.Property2_int); 48 | Assert.AreEqual("10.0.0.2", receivedClient.IPAddress); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Utilities/MockNetworkChannelFactory.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using OTransport; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace Test 9 | { 10 | class MockNetworkChannelFactory 11 | { 12 | public static Tuple GetConnectedChannels() 13 | { 14 | var channel1 = new Mock(); 15 | var channel2 = new Mock(); 16 | 17 | Action channel1ReceiveFunction = null; 18 | Action channel2ReceiveFunction = null; 19 | 20 | var channel1Client = new Client("10.0.0.1", 123); 21 | var channel2Client = new Client("10.0.0.2", 321); 22 | 23 | Action channel1OnClient = null; 24 | Action channel2OnClient = null; 25 | 26 | 27 | channel1.Setup(c => c.Send(It.IsAny(), It.IsAny())).Callback((c, p) => 28 | { 29 | ReceivedMessage message = new ReceivedMessage(channel1Client, p); 30 | channel2ReceiveFunction.Invoke(message); 31 | }); 32 | 33 | channel1.Setup(c => c.OnReceive(It.IsAny>())).Callback>( 34 | function => channel1ReceiveFunction = function 35 | ); 36 | 37 | channel2.Setup(c => c.Send(It.IsAny(), It.IsAny())).Callback((c, p) => 38 | { 39 | ReceivedMessage message = new ReceivedMessage(channel2Client, p); 40 | channel1ReceiveFunction.Invoke(message); 41 | }); 42 | 43 | channel2.Setup(c => c.OnReceive(It.IsAny>())).Callback>( 44 | function => channel2ReceiveFunction = function 45 | ); 46 | 47 | channel2.Setup(c => c.OnClientConnect(It.IsAny>())).Callback>(a => 48 | { 49 | channel2OnClient = a; 50 | channel2OnClient.Invoke(channel1Client); 51 | }); 52 | 53 | channel1.Setup(c => c.OnClientConnect(It.IsAny>())).Callback>(a => 54 | { 55 | channel1OnClient = a; 56 | channel1OnClient.Invoke(channel2Client); 57 | }); 58 | 59 | Tuple channels = new Tuple(channel1.Object,channel2.Object); 60 | 61 | return channels; 62 | } 63 | public static MockedNetworkChannel GetMockedNetworkChannel() 64 | { 65 | MockedNetworkChannel mock = new MockedNetworkChannel(); 66 | return mock; 67 | } 68 | 69 | 70 | } 71 | public class MockedNetworkChannel : INetworkChannel 72 | { 73 | private Action MockSendFunction = null; 74 | 75 | private Action ObjectTransportReceive = null; 76 | private Action ObjectTransportClientConnect = null; 77 | 78 | public int LocalPort => throw new NotImplementedException(); 79 | 80 | public MockedNetworkChannel OnSendHandle(Action sendFunction) 81 | { 82 | MockSendFunction = sendFunction; 83 | return this; 84 | } 85 | 86 | public void SendUnreliable(Client client, string message) 87 | { 88 | } 89 | 90 | public void SimulateClientConnect(Client client) 91 | { 92 | ObjectTransportClientConnect.Invoke(client); 93 | } 94 | 95 | public void SimulateClientResponse(Client client,string message) 96 | { 97 | ReceivedMessage receivedMessage = new ReceivedMessage(client,message); 98 | ObjectTransportReceive.Invoke(receivedMessage); 99 | } 100 | 101 | public void Stop() 102 | { 103 | 104 | } 105 | 106 | public void SetReliable() 107 | { 108 | } 109 | 110 | public void SetUnreliable() 111 | { 112 | } 113 | 114 | public void OnClientConnect(Action callBack) 115 | { 116 | ObjectTransportClientConnect = callBack; 117 | } 118 | 119 | public void OnReceive(Action callBack) 120 | { 121 | ObjectTransportReceive = callBack; 122 | } 123 | 124 | public void OnClientDisconnect(Action callBack) 125 | { 126 | } 127 | 128 | public void Send(Client client, string payload) 129 | { 130 | if(MockSendFunction!=null) 131 | MockSendFunction.Invoke(client, payload); 132 | } 133 | 134 | public void DisconnectClient(params Client[] client) 135 | { 136 | throw new NotImplementedException(); 137 | } 138 | 139 | public void Start(string ipaddress, int port) 140 | { 141 | throw new NotImplementedException(); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Utilities/MockObjectMessage.cs: -------------------------------------------------------------------------------- 1 | namespace OTransport.tests 2 | { 3 | public class MockObjectMessage 4 | { 5 | public string Property1_string { get; set; } 6 | public int Property2_int { get; set; } 7 | public decimal Property3_decimal { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Utilities/MockObjectMessageWithBinary.cs: -------------------------------------------------------------------------------- 1 | namespace OTransport.tests 2 | { 3 | public class MockObjectMessageWithBinary 4 | { 5 | public byte[] Property1_Bytes { get; set; } 6 | public string Property2_String { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Utilities/TestObjectTransportFactory.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Serializer.JSON; 2 | using OTransport; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using OTransport.Serializer; 7 | 8 | namespace OTransport.Test.Utilities 9 | { 10 | public static class TestObjectTransportFactory 11 | { 12 | public static ObjectTransport CreateNewObjectTransport(INetworkChannel channel) 13 | { 14 | var jsonSerializer = new JSONserializer(); 15 | 16 | return new ObjectTransport(channel, jsonSerializer); 17 | } 18 | public static ObjectTransport CreateNewObjectTransport(INetworkChannel channel,ISerializer serializer) 19 | { 20 | return new ObjectTransport(channel, serializer); 21 | } 22 | 23 | internal static ObjectTransport CreateNewObjectTransportTCPclient() 24 | { 25 | var tcpClient = new NetworkChannel.TCP.TCPClientChannel(); 26 | var jsonSerializer = new JSONserializer(); 27 | 28 | return new ObjectTransport(tcpClient, jsonSerializer); 29 | } 30 | internal static ObjectTransport CreateNewObjectTransportUDPclient() 31 | { 32 | var udpClient = new NetworkChannel.UDP.UDPClientChannel(); 33 | var jsonSerializer = new JSONserializer(); 34 | 35 | return new ObjectTransport(udpClient, jsonSerializer); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ObjectTransport.tests/Utilities/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using OTransport.tests; 5 | using System.Threading; 6 | 7 | namespace Test 8 | { 9 | class Utilities 10 | { 11 | public static void WaitFor(ref string test) 12 | { 13 | while(test == string.Empty || test == null) { } 14 | } 15 | 16 | internal static void WaitFor(ref bool executed) 17 | { 18 | while(executed == false) { } 19 | } 20 | 21 | internal static void WaitFor(ref T Object) 22 | { 23 | while(Object == null) { } 24 | } 25 | 26 | internal static void Wait() 27 | { 28 | Thread.Sleep(10); 29 | } 30 | 31 | internal static void WaitFor(Func check) 32 | { 33 | 34 | while (!check.Invoke()) { } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ObjectTransport/Client.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport 6 | { 7 | public class Client 8 | { 9 | internal Client() 10 | { 11 | 12 | } 13 | public Client(string ipaddress,int port) 14 | { 15 | IPAddress = ipaddress; 16 | Port = port; 17 | } 18 | 19 | public string IPAddress { get; internal set; } 20 | public int Port { get; internal set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ObjectTransport/Factory/ObjectTransportAssemblyLine.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Serializer; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace OTransport.Factory 7 | { 8 | public class ObjectTransportAssemblyLine 9 | { 10 | private INetworkChannel NetworkChannel; 11 | private ISerializer Serializer; 12 | private bool Reliable = false; 13 | 14 | public void SetNetworkChannel(INetworkChannel networkChannel) 15 | { 16 | NetworkChannel = networkChannel; 17 | } 18 | 19 | /// 20 | /// Specify a custom serializer to be used when serilizing objects. 21 | /// 22 | /// 23 | /// 24 | public ObjectTransportAssemblyLine SetSerializer(ISerializer serializer) 25 | { 26 | Serializer = serializer; 27 | return this; 28 | } 29 | 30 | public void SetReliableTransport() 31 | { 32 | Reliable = true; 33 | } 34 | public void SetUnreliableTransport() 35 | { 36 | Reliable = false; 37 | } 38 | 39 | public IObjectTransport Build() 40 | { 41 | if (Serializer == null) 42 | throw new ObjectTransportException("Please specify a Serializer to use. If you haven't done so, please install a serializer from nuget or implement your own."); 43 | 44 | var objectTransport = new ObjectTransport(NetworkChannel, Serializer); 45 | 46 | if (Reliable) 47 | objectTransport.SetReliable(); 48 | else 49 | objectTransport.SetUnreliable(); 50 | 51 | return objectTransport; 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ObjectTransport/Factory/ObjectTransportFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport 6 | { 7 | public class ObjectTransportFactory 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ObjectTransport/IObjectTransport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace OTransport 5 | { 6 | public interface IObjectTransport 7 | { 8 | /// 9 | /// Disconnects the first client that is connected. This is best used when the current object transport is a client connected to a server. 10 | /// 11 | void DisconnectClient(); 12 | /// 13 | /// Disconnects the given client. If this is a client connected to a server, only the server can be passed in. Call DisconnectClient() instead. 14 | /// 15 | /// 16 | void DisconnectClient(params Client[] client); 17 | /// 18 | /// This function will return a list of all clients that are currently connected. 19 | /// 20 | /// IEnumerable of connected clients 21 | IEnumerable GetConnectedClients(); 22 | /// 23 | /// Set the function/lambda to be called when a client connects. 24 | /// 25 | /// The function/lambda to call when a client connects 26 | void OnClientConnect(Action onConnectFunction); 27 | /// 28 | /// Set the function/lambda to be called when a client disconnects 29 | /// 30 | /// The function/lambda to call when a client disconnects 31 | void OnClientDisconnect(Action onDisconnectFunction); 32 | /// 33 | /// Use this method to handle the event when receiving a message fails to be processed by object transport. 34 | /// The first parameter is the Received message. This contains the message body as a string and the client who sent the message. 35 | /// The Second parameter is the exception that was thrown to cause the receive to fail. 36 | /// 37 | void OnFailedReceive(Action onfail); 38 | /// 39 | /// Setup a listener to execute when an object is received of the given type. This will execute the given function/lambda and pass in the object that was received. 40 | /// 41 | /// The received object type to listen for and handle. 42 | /// The function/lambda to execute when an object of the specified type is received. This function will have the object passed in as a parameter. 43 | /// 44 | MessageReceive Receive(); 45 | /// 46 | /// Setup a listener to execute when an object is received of the given type. This will execute the given function/lambda and pass in the object that was received as well as the client who sent the object. 47 | /// 48 | /// The received object type to listen for and handle. 49 | /// The function/lambda to execute when an object of the specified type is received. This function will have the object passed in as a parameter. It will also have the client passed in. 50 | /// 51 | MessageReceive Receive(Action obj); 52 | /// 53 | /// Setup a listener to execute when an object is received of the given type. This will execute the given function/lambda and pass in the object that was received. 54 | /// 55 | /// The received object type to listen for and handle. 56 | /// The function/lambda to execute when an object of the specified type is received. This function will have the object passed in as a parameter. 57 | /// 58 | MessageReceive Receive(Action function); 59 | /// 60 | /// Send an object through the network channel 61 | /// 62 | /// The type of the object being sent. 63 | /// The object to send. 64 | /// 65 | MessageSend Send(SendType obj); 66 | /// 67 | /// Make any subsequent messages default to reliable. The underlining network channel will throw an exception if it is not supported 68 | /// 69 | void SetReliable(); 70 | /// 71 | /// Make any subsequent messages default to unreliable. The underlining network channel will throw an exception if it is not supported 72 | /// 73 | void SetUnreliable(); 74 | /// 75 | /// Stop the underlying channel 76 | /// 77 | void Stop(); 78 | 79 | 80 | /// 81 | /// Start the object transport. If this is a client, this will connect to the target IP and port. 82 | /// If this is a server, this will start a server on the given ip and port. 83 | /// 84 | /// 85 | /// 86 | IObjectTransport Start(string ipaddress, int port); 87 | } 88 | } -------------------------------------------------------------------------------- /ObjectTransport/MessageReceive.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace OTransport 5 | { 6 | public class MessageReceive 7 | { 8 | ReceivedMessageHandle handle = new ReceivedMessageHandle(); 9 | private ObjectTransport ObjectTransport; 10 | 11 | internal MessageReceive(Delegate actionReceived,ObjectTransport objectTransport) 12 | { 13 | handle.ReceiveAction = actionReceived; 14 | ObjectTransport = objectTransport; 15 | } 16 | 17 | internal MessageReceive(ObjectTransport objectTransport) 18 | { 19 | ObjectTransport = objectTransport; 20 | } 21 | 22 | /// 23 | /// After receiving an object, execute a function/lambda. What ever this function/lambda returns will be sent back to the client who sent the original message. The original object that was received is passed as a paramter to the function/lambda. 24 | /// 25 | /// the function/lambda to execute to get a reply object to send back. 26 | /// 27 | public MessageReceive Reply(Func replyFunction) 28 | { 29 | handle.ReplyFunction = replyFunction; 30 | return this; 31 | } 32 | 33 | /// 34 | /// After receiving an object, execute a function/lambda. What ever this function/lambda returns will be sent back to the client who sent the original message. The original object that was received as well as the client who sent the original object is passed as a paramter to the function/lambda. 35 | /// 36 | /// the function/lambda to execute to get a reply object to send back. 37 | /// 38 | public MessageReceive Reply(Func replyFunction) 39 | { 40 | handle.ReplyFunction = replyFunction; 41 | return this; 42 | } 43 | 44 | /// 45 | /// Execute and begin listening for objects of the given type to be received. 46 | /// 47 | public void Execute() 48 | { 49 | handle.RecieveType = typeof(ReceivedType); 50 | ObjectTransport.AddToListenerHandles(handle); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ObjectTransport/MessageResponseHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport 6 | { 7 | internal class MessageResponseHandle 8 | { 9 | public MessageResponseHandle(QueuedMessage sent) 10 | { 11 | sentMessage = sent; 12 | } 13 | 14 | public List ClientsToRespond = new List(); 15 | 16 | public QueuedMessage sentMessage { get; set; } 17 | public int SecondsPassed { get; set; } = 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ObjectTransport/MessageSend.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace OTransport 6 | { 7 | public class MessageSend 8 | { 9 | private QueuedMessage message = new QueuedMessage(); 10 | private ObjectTransport ObjectTransport; 11 | 12 | internal MessageSend(SendType sendObject,ObjectTransport objectTransport) 13 | { 14 | message.ObjectToSend = sendObject; 15 | message.sendTo = objectTransport.GetConnectedClients().ToArray(); 16 | ObjectTransport = objectTransport; 17 | message.SendReliable = ObjectTransport.SendReliable; 18 | } 19 | 20 | /// 21 | /// After sending an object, wait for a response back. If the response is of the given object type, execute the given function/lambda. The received object is fed into the function/lambda. 22 | /// The client who the object was sent to must respond with the reply function 23 | /// 24 | /// The object type to handle 25 | /// the function/lambda to execute when an object of the given type is received 26 | /// 27 | public MessageSend Response(Action onResponseFunction) 28 | { 29 | message.resonseType_to_actionMatch.Add(typeof(ResponseType), onResponseFunction); 30 | return this; 31 | } 32 | 33 | /// 34 | /// When a response is expected after sending an object but the timeout has run out, a handler will execute. This function sets the timeout function/lambda. 35 | /// 36 | /// The function/lambda to execute. An array of Clients who did not respond and the object that was sent is passed as parameters. 37 | /// 38 | public MessageSend OnTimeOut(Action function) 39 | { 40 | message.TimeOutFunction = function; 41 | return this; 42 | } 43 | 44 | /// 45 | /// After sending an object, wait for a response back. If the response is of the given object type, execute the given function/lambda. The received object as well as the client who sent it is fed into the function/lambda. 46 | /// The client who the object was sent to must respond with the reply function 47 | /// 48 | /// The object type to handle 49 | /// the function/lambda to execute when an object of the given type is received 50 | /// 51 | public MessageSend Response(Action onResponseFunction) 52 | { 53 | message.resonseType_to_actionMatch.Add(typeof(ResponseType), onResponseFunction); 54 | return this; 55 | } 56 | 57 | /// 58 | /// If there has been no response for the given amount of time, stop listening for responses 59 | /// 60 | /// The number of seconds to wait for a response 61 | /// 62 | public MessageSend SetTimeOut(int seconds) 63 | { 64 | message.TimeOutInSeconds = seconds; 65 | return this; 66 | } 67 | /// 68 | /// The client to send the message to. This is not needed if the message is going to a Server. 69 | /// 70 | /// 71 | /// 72 | public MessageSend To(params Client[] client) 73 | { 74 | message.sendTo = client; 75 | return this; 76 | } 77 | 78 | /// 79 | /// Send the given object to the client and listen for any responses back from the client 80 | /// 81 | public void Execute() 82 | { 83 | ObjectTransport.Send(message); 84 | } 85 | 86 | /// 87 | /// Send the object to all clients. 88 | /// 89 | /// 90 | public MessageSend ToAll() 91 | { 92 | message.sendTo = ObjectTransport.GetConnectedClients().ToArray(); 93 | return this; 94 | } 95 | /// 96 | /// Send the object to all clients except the given clients 97 | /// 98 | /// Clients to exclude 99 | /// 100 | public MessageSend ToAllExcept(params Client [] except) 101 | { 102 | message.sendTo = ObjectTransport.GetConnectedClients().Where(c => !except.Contains(c)).ToArray(); 103 | return this; 104 | } 105 | 106 | /// 107 | /// Send the object reliably over the given network channel if it is supported. If it is not supported, the channel will throw an exception. 108 | /// 109 | /// 110 | public MessageSend Reliable() 111 | { 112 | message.SendReliable = true; 113 | return this; 114 | } 115 | 116 | /// 117 | /// Send the object unreliably over the given network channel if it is supported. If it is not supported, the channel will throw an exception. 118 | /// 119 | /// 120 | public MessageSend Unreliable() 121 | { 122 | message.SendReliable = false; 123 | return this; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /ObjectTransport/Network Channels/INetworkChannel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport 6 | { 7 | public interface INetworkChannel 8 | { 9 | int LocalPort { get; } 10 | void Stop(); 11 | void SetReliable(); 12 | void SetUnreliable(); 13 | void OnClientConnect(Action callBack); 14 | void OnReceive(Action callBack); 15 | void OnClientDisconnect(Action callBack); 16 | void Send(Client client, string payload); 17 | void DisconnectClient(params Client[] client); 18 | void Start(string ipaddress, int port); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ObjectTransport/ObjectTransport.cs: -------------------------------------------------------------------------------- 1 | using OTransport.Factory; 2 | using OTransport.Serializer; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Threading; 9 | 10 | namespace OTransport 11 | { 12 | public class ObjectTransport : IObjectTransport 13 | { 14 | public static ObjectTransportFactory Factory = new ObjectTransportFactory(); 15 | List clients = new List(); 16 | private readonly INetworkChannel NetworkChannel; 17 | private readonly ISerializer Serializer; 18 | 19 | private ConcurrentDictionary ResponseHandle = new ConcurrentDictionary(); 20 | private ConcurrentDictionary ReceiveHandle = new ConcurrentDictionary(); 21 | private Action OnClientConnectHandler = null; 22 | private Action onClientDisconnectHandler = null; 23 | private Action OnFailedReceiveHandler = null; 24 | 25 | internal bool SendReliable = true; 26 | private readonly int TokenLength = 8; 27 | 28 | public ObjectTransport(INetworkChannel networkChannel, ISerializer serializer) 29 | { 30 | NetworkChannel = networkChannel; 31 | Serializer = serializer; 32 | 33 | TimeOutCheck(); 34 | SetupNetworkReceiveCallback(); 35 | SetUpClientConnectCallback(); 36 | } 37 | 38 | /// 39 | /// Make any subsequent messages default to reliable. The underlining network channel will throw an exception if it is not supported 40 | /// 41 | public void SetReliable() 42 | { 43 | SendReliable = true; 44 | } 45 | 46 | /// 47 | /// Make any subsequent messages default to unreliable. The underlining network channel will throw an exception if it is not supported 48 | /// 49 | public void SetUnreliable() 50 | { 51 | SendReliable = false; 52 | } 53 | /// 54 | /// This function will return a list of all clients that are currently connected. 55 | /// 56 | /// IEnumerable of connected clients 57 | public IEnumerable GetConnectedClients() 58 | { 59 | return clients; 60 | } 61 | 62 | /// 63 | /// Set the function/lambda to be called when a client connects. 64 | /// 65 | /// The function/lambda to call when a client connects 66 | public void OnClientConnect(Action onConnectFunction) 67 | { 68 | OnClientConnectHandler = onConnectFunction; 69 | } 70 | /// 71 | /// Set the function/lambda to be called when a client disconnects 72 | /// 73 | /// The function/lambda to call when a client disconnects 74 | public void OnClientDisconnect(Action onDisconnectFunction) 75 | { 76 | onClientDisconnectHandler = onDisconnectFunction; 77 | } 78 | 79 | private void TimeOutCheck() 80 | { 81 | Timer timer = new Timer(o => 82 | { 83 | IEnumerable keys = ResponseHandle.Keys; 84 | foreach(var key in keys) 85 | { 86 | MessageResponseHandle handler; 87 | while(!ResponseHandle.TryGetValue(key, out handler)){ } 88 | 89 | if (handler == null) 90 | continue; 91 | 92 | handler.SecondsPassed += 1; 93 | 94 | if(handler.SecondsPassed >= handler.sentMessage.TimeOutInSeconds) 95 | { 96 | while (!ResponseHandle.TryRemove(key,out handler)) { } 97 | 98 | if (handler.sentMessage.TimeOutFunction != null) 99 | handler.sentMessage.TimeOutFunction.DynamicInvoke(handler.ClientsToRespond.ToArray(), handler.sentMessage.ObjectToSend); 100 | } 101 | 102 | } 103 | 104 | }, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); 105 | } 106 | 107 | private void SetupNetworkReceiveCallback() 108 | { 109 | //Set a callback for the network channel 110 | 111 | NetworkChannel.OnReceive((message) => 112 | { 113 | try 114 | { 115 | (Type, string, string) objectType_token_objectPayload = ParseRecievedMessage(message.Message); 116 | 117 | Type receivedObjectType = objectType_token_objectPayload.Item1; 118 | string token = objectType_token_objectPayload.Item2; 119 | string objectPayload = objectType_token_objectPayload.Item3; 120 | 121 | if (receivedObjectType == null) 122 | return; 123 | 124 | object receivedObject = Serializer.Deserialize(objectPayload, receivedObjectType); 125 | 126 | if (token != null && ResponseHandle.ContainsKey(token)) 127 | { 128 | CheckExecuteResponseHandle(message, receivedObjectType, token, receivedObject); 129 | } 130 | else if (ReceiveHandle.ContainsKey(receivedObjectType)) 131 | { 132 | CheckExecuteReceiveAction(message, receivedObjectType, receivedObject); 133 | CheckExecuteReplyAction(message, receivedObjectType, token, receivedObject); 134 | } 135 | } 136 | catch(Exception e) 137 | { 138 | //Error parsing the message. Invoke the OnFailedReceiveHandler. 139 | OnFailedReceiveHandler?.Invoke(message, e); 140 | return; 141 | } 142 | }); 143 | } 144 | 145 | /// 146 | /// Use this method to handle the event when receiving a message fails to be processed by object transport. 147 | /// The first parameter is the Received message. This contains the message body as a string and the client who sent the message. 148 | /// The Second parameter is the exception that was thrown to cause the receive to fail. 149 | /// 150 | public void OnFailedReceive(Action onfail) 151 | { 152 | OnFailedReceiveHandler = onfail; 153 | } 154 | 155 | /// 156 | /// Disconnects the given client. If this is a client connected to a server, only the server can be passed in. Call DisconnectClient() instead. 157 | /// 158 | /// 159 | public void DisconnectClient(params Client[] client) 160 | { 161 | NetworkChannel.DisconnectClient(client); 162 | } 163 | /// 164 | /// Disconnects the first client that is connected. This is best used when the current object transport is a client connected to a server. 165 | /// 166 | public void DisconnectClient() 167 | { 168 | 169 | if (this.clients.Count() > 0) 170 | { 171 | NetworkChannel.DisconnectClient(this.clients.First()); 172 | } 173 | } 174 | 175 | private (Type, string, string) ParseRecievedMessage(string message) 176 | { 177 | int firstDivide = message.IndexOf("::"); 178 | var typeName = message.Substring(0, firstDivide); 179 | 180 | Type returnType = Type.GetType(typeName); 181 | var payload = message.Substring(firstDivide + 2); 182 | string token = null; 183 | 184 | int secondDivide = payload.IndexOf("::"); 185 | 186 | if(secondDivide > -1 && secondDivide == TokenLength) 187 | { 188 | token = payload.Substring(0, secondDivide); 189 | payload = payload.Substring(secondDivide + 2); 190 | } 191 | 192 | return (returnType,token,payload); 193 | } 194 | 195 | private void CheckExecuteResponseHandle(ReceivedMessage message, Type receivedObjectType, string token, object receivedObject) 196 | { 197 | var responseType_ActionMatch = ResponseHandle[token].sentMessage.resonseType_to_actionMatch; 198 | if (responseType_ActionMatch.ContainsKey(receivedObjectType)) 199 | { 200 | Delegate responseHandle = responseType_ActionMatch[receivedObjectType]; 201 | if (responseHandle.GetMethodInfo().GetParameters().Count() > 1) 202 | { 203 | responseHandle.DynamicInvoke(message.From, receivedObject); 204 | } 205 | else 206 | { 207 | responseHandle.DynamicInvoke(receivedObject); 208 | } 209 | 210 | //Remove the client from the list of clients who still need to respond 211 | ResponseHandle[token].ClientsToRespond.Remove(message.From); 212 | } 213 | } 214 | 215 | private void CheckExecuteReceiveAction(ReceivedMessage message,Type receivedObjectType, object receivedObject) 216 | { 217 | Delegate receiveAction = ReceiveHandle[receivedObjectType].ReceiveAction; 218 | if (receiveAction != null) 219 | { 220 | if (receiveAction.GetMethodInfo().GetParameters().Count() > 1) 221 | { 222 | receiveAction.DynamicInvoke(message.From, receivedObject); 223 | } 224 | else 225 | { 226 | receiveAction.DynamicInvoke(receivedObject); 227 | } 228 | 229 | } 230 | } 231 | 232 | private void CheckExecuteReplyAction(ReceivedMessage message, Type receivedObjectType, string token, object receivedObject) 233 | { 234 | Delegate replyFunction = ReceiveHandle[receivedObjectType].ReplyFunction; 235 | if (replyFunction != null) 236 | { 237 | object result; 238 | if (replyFunction.GetMethodInfo().GetParameters().Count() > 1) 239 | result = replyFunction.DynamicInvoke(message.From, receivedObject); 240 | else 241 | result = replyFunction.DynamicInvoke(receivedObject); 242 | 243 | if (result == null) 244 | return; 245 | 246 | QueuedMessage queueMessage = new QueuedMessage(); 247 | queueMessage.ObjectToSend = result; 248 | queueMessage.sendTo = new Client[] { message.From }; 249 | queueMessage.SendReliable = SendReliable; 250 | queueMessage.Token = token; 251 | Send(queueMessage); 252 | } 253 | } 254 | 255 | private void SetUpClientConnectCallback() 256 | { 257 | NetworkChannel.OnClientConnect((client)=> 258 | { 259 | clients.Add(client); 260 | OnClientConnectHandler?.Invoke(client); 261 | }); 262 | 263 | NetworkChannel.OnClientDisconnect((client)=> 264 | { 265 | clients.Remove(client); 266 | onClientDisconnectHandler?.Invoke(client); 267 | }); 268 | } 269 | 270 | private string GenerateToken() 271 | { 272 | //Get the first 8 characters of a newly generated token 273 | return Guid.NewGuid().ToString().Split('-')[0]; 274 | } 275 | private string GetPayload(QueuedMessage send) 276 | { 277 | object objectToSend = send.ObjectToSend; 278 | Type objectType = objectToSend.GetType(); 279 | 280 | string object_AssemblyQualifiedName = objectType.AssemblyQualifiedName; 281 | string serialized_object = Serializer.Serialize(objectToSend); 282 | 283 | string token = send.Token; 284 | 285 | //If this queued message is waiting for a response eg (Send().Response()) 286 | if (send.resonseType_to_actionMatch.Count > 0) 287 | { 288 | token = GenerateToken(); 289 | 290 | MessageResponseHandle responseHandle = new MessageResponseHandle(send); 291 | responseHandle.ClientsToRespond.AddRange(send.sendTo); 292 | ResponseHandle.TryAdd(token, responseHandle); 293 | } 294 | 295 | string payload = string.Empty; 296 | 297 | if(token == null) 298 | payload = string.Format("{0}::{1}", object_AssemblyQualifiedName, serialized_object); 299 | else 300 | payload = string.Format("{0}::{1}::{2}", object_AssemblyQualifiedName, token, serialized_object); 301 | 302 | return payload; 303 | } 304 | internal void Send(QueuedMessage send) 305 | { 306 | if (clients.Count == 0) 307 | return; 308 | 309 | Client[] clientsTo = send.sendTo; 310 | 311 | send.sendTo = clientsTo; 312 | 313 | string payload = GetPayload(send); 314 | 315 | foreach (Client client in clientsTo) 316 | { 317 | if (send.SendReliable) 318 | NetworkChannel.SetReliable(); 319 | else 320 | NetworkChannel.SetUnreliable(); 321 | 322 | NetworkChannel.Send(client, payload); 323 | } 324 | } 325 | /// 326 | /// Stop the underlying channel 327 | /// 328 | public void Stop() 329 | { 330 | NetworkChannel.Stop(); 331 | } 332 | 333 | /// 334 | /// Send an object through the network channel 335 | /// 336 | /// The type of the object being sent. 337 | /// The object to send. 338 | /// 339 | public MessageSend Send(SendType obj) 340 | { 341 | var messageSend = new MessageSend(obj,this); 342 | 343 | return messageSend; 344 | } 345 | internal void AddToListenerHandles(ReceivedMessageHandle handle) 346 | { 347 | Type type = handle.RecieveType; 348 | if (ReceiveHandle.ContainsKey(type)) 349 | throw new ObjectTransportException("This object type is already being handled"); 350 | 351 | while(!ReceiveHandle.TryAdd(type, handle)) { } 352 | } 353 | /// 354 | /// Setup a listener to execute when an object is received of the given type. This will execute the given function/lambda and pass in the object that was received. 355 | /// 356 | /// The received object type to listen for and handle. 357 | /// The function/lambda to execute when an object of the specified type is received. This function will have the object passed in as a parameter. 358 | /// 359 | public MessageReceive Receive(Action function) 360 | { 361 | return new MessageReceive(function,this); 362 | } 363 | 364 | /// 365 | /// Setup a listener to execute when an object is received of the given type. This will execute the given function/lambda and pass in the object that was received as well as the client who sent the object. 366 | /// 367 | /// The received object type to listen for and handle. 368 | /// The function/lambda to execute when an object of the specified type is received. This function will have the object passed in as a parameter. It will also have the client passed in. 369 | /// 370 | public MessageReceive Receive(Action obj) 371 | { 372 | return new MessageReceive(obj,this); 373 | } 374 | /// 375 | /// Setup a listener to execute when an object is received of the given type. 376 | /// 377 | /// The received object type to listen for and handle. 378 | /// 379 | public MessageReceive Receive() 380 | { 381 | return new MessageReceive(this); 382 | } 383 | 384 | public IObjectTransport Start(string ipaddress, int port) 385 | { 386 | NetworkChannel.Start(ipaddress, port); 387 | return this; 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /ObjectTransport/ObjectTransport.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PackageReference 5 | netstandard1.6;netcoreapp1.1;net46 6 | OTransport 7 | ObjectTransport 8 | 1.1.3 9 | Rhyno van der Sluijs 10 | 11 | A simple lightweight library that allows you to send and receive Objects over TCP or UDP. This assembly contains the project interfaces as well as abstract implementations. You must install the implementations to use this framework. 12 | Please see the following link for more information about installing ObjectTransport: 13 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 14 | 15 | false 16 | 17 | This release introduces the DisconnectClient function which allows you to disconnect a connected client. 18 | 19 | 20 | TCP Server Object networking UDP 21 | https://github.com/RhynoVDS/ObjectTransport 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | true 44 | Content 45 | true 46 | Always 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /ObjectTransport/ObjectTransportException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OTransport 4 | { 5 | public class ObjectTransportException : Exception 6 | { 7 | public ObjectTransportException() 8 | { 9 | } 10 | 11 | public ObjectTransportException(string message) : base(message) 12 | { 13 | } 14 | 15 | public ObjectTransportException(string message, Exception innerException) : base(message, innerException) 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /ObjectTransport/PayLoad/QueuedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace OTransport 6 | { 7 | internal class QueuedMessage 8 | { 9 | public Dictionary resonseType_to_actionMatch { get; set; } = new Dictionary(); 10 | public int TimeOutInSeconds { get; set; } = 15; 11 | public object ObjectToSend { get; set; } 12 | public string Token { get; set; } 13 | public Client[] sendTo { get; set; } 14 | public Delegate TimeOutFunction { get; set; } 15 | 16 | public bool SendReliable { get; set; } 17 | 18 | } 19 | } -------------------------------------------------------------------------------- /ObjectTransport/PayLoad/ReceivedConnection.cs: -------------------------------------------------------------------------------- 1 | namespace OTransport 2 | { 3 | public class ReceivedConnection 4 | { 5 | public string Address { get; set; } 6 | public int Port { get; set; } 7 | 8 | public ReceivedConnection(string address,int port) 9 | { 10 | Address = address; 11 | Port = port; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ObjectTransport/PayLoad/ReceivedMessage.cs: -------------------------------------------------------------------------------- 1 | namespace OTransport 2 | { 3 | public class ReceivedMessage 4 | { 5 | public Client From { get; } 6 | public string Message { get; } 7 | 8 | public ReceivedMessage(Client client, string message) 9 | { 10 | From = client; 11 | Message = message; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ObjectTransport/ReceivedMessageHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport 6 | { 7 | class ReceivedMessageHandle 8 | { 9 | public Type RecieveType { get; set; } 10 | public Delegate ReceiveAction { get; set; } 11 | public Delegate ReplyFunction { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ObjectTransport/Serializer/ISerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace OTransport.Serializer 6 | { 7 | public interface ISerializer 8 | { 9 | string Serialize(object obj); 10 | object Deserialize(string objectPayload, Type objectType); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # ObjectTransport 4 | 5 | A lightweight library that allows you to send and receive objects over TCP or UDP. ObjectTranport aims to be a network framework that is as simple and lightweight as possible. 6 | 7 | Multiple serialization options are available such as Protobuf. Serialization is injectable and you can implement your own. 8 | 9 | ## Install 10 | 11 | ObjectTransport is split into seperate packages based off your needs and available on nuget. Plese see installation instructions for more details: 12 | https://github.com/RhynoVDS/ObjectTransport/wiki/Installation 13 | 14 | ## Simple Example 15 | 16 | ### Starting the server 17 | 18 | You can start a TCP server with the following code: 19 | 20 | ```csharp 21 | 22 | var server = ObjectTransport.Factory.CreateTCPServer() 23 | .UseJSONserialization(); 24 | .Build(); 25 | 26 | //Start the TCP server on port 123 27 | server.Start("127.0.0.1",123); 28 | ``` 29 | 30 | or you can start a UDP server 31 | 32 | ```csharp 33 | var server = ObjectTransport.Factory.CreateUDPServer() 34 | .UseJSONserialization(); 35 | .Build(); 36 | 37 | //Start the UDP server on port 123 38 | server.Start("127.0.0.1",123); 39 | 40 | ``` 41 | 42 | ### Receiving an Object 43 | 44 | In this example we have a scenario where we want to handle a user logging into the server. Suppose we have a simple class called "LoginModel". For now this class only has the field "Username" 45 | 46 | ```csharp 47 | public class LoginModel 48 | { 49 | public string Username {get;set;} 50 | } 51 | ``` 52 | 53 | We want the server to receive this object and handle it. This can be done using the "Receive" function: 54 | 55 | ```csharp 56 | server.Receive(lm => 57 | { 58 | Console.WriteLine(lm.Username); 59 | }) 60 | .Execute(); 61 | ``` 62 | 63 | In the above code, we specify that when the server Receives an object of type "LoginModel", execute the given lambda. We then write the Username to the console. 64 | 65 | It is possible to set up multiple Receive functions and handle other types: 66 | 67 | ```csharp 68 | server.Receive(lm => ... ).Execute(); 69 | 70 | server.Receive(lm => ... ).Execute(); 71 | 72 | server.Receive(lm => ... ).Execute(); 73 | ... 74 | ``` 75 | 76 | ### Starting the client 77 | 78 | You can start a TCP client with the following code: 79 | 80 | ```csharp 81 | var client = ObjectTransport.Factory.CreateTCPClient() 82 | .UseJSONserialization(); 83 | .Build(); 84 | 85 | //Start the client and connect to the target IP address and port 86 | client.Start("10.0.0.1",123); 87 | ``` 88 | 89 | To send an object over the channel, use the "Send" function: 90 | 91 | ```csharp 92 | var loginRequest = new LoginModel() 93 | loginRequest.Username = "TestUser"; 94 | 95 | client.Send(loginRequest).Execute(); 96 | ``` 97 | 98 | ## Setting up multiple responses 99 | 100 | In the following example, we will show how a server/client can reply to a received object. 101 | 102 | In our previous example, we are currently sending a Username to the server but not our password, which isn't very secure. In this example, we update our model to have a "Password" field: 103 | 104 | ```csharp 105 | public class LoginModel 106 | { 107 | public string Username {get;set;} 108 | public string Password {get;set;} 109 | } 110 | ``` 111 | 112 | ### Sending Login Request from the client 113 | 114 | Our client needs to send a login request to the server and will now need to send their password as well. Due to this, we want to handle any responses to our request including whether or not the login was successful. To handle this, we create two new classes "LoginSuccess" and "LoginFailure". 115 | 116 | ```csharp 117 | public class LoginSuccess 118 | { 119 | public string Name {get;set;} 120 | public string Password {get;set;} 121 | } 122 | 123 | public class LoginFailure 124 | { 125 | public string Message {get;set;} 126 | } 127 | ``` 128 | 129 | 130 | In our client code, we will now use the "Response" function after sending the login object. When the server replies to the object that was sent, the client will handle it's responses: 131 | 132 | ```csharp 133 | var transport = ObjectTransport.Factory.CreateTCPClient("10.0.0.1",123); 134 | 135 | var loginRequest = new LoginModel(); 136 | loginRequest.Username = "TestUser"; 137 | loginRequest.Password = "A password"; 138 | 139 | transport.Send(loginRequest) 140 | .Response(ls=>{ 141 | Console.WriteLine("Welcome Back {0}", ls.Name); 142 | }) 143 | .Response(lr=>{ 144 | Console.WriteLine(lr.Message) 145 | }) 146 | .Execute(); 147 | 148 | ``` 149 | In the above example, we setup 2 response handles, one to handle "LoginSuccess" and another to handle "LoginFailure". 150 | 151 | On the server, we will use the "Reply" function after receiving a login model. When using this function we need use a function/lambda which will "return" an object that will be sent back: 152 | 153 | ```csharp 154 | 155 | server.Receive() 156 | .Reply(lr=> { 157 | 158 | string user = string.empty; 159 | //Check if login is valid 160 | 161 | if(utilities.Login(lr, out user)) 162 | { 163 | 164 | //Return an object back to the client 165 | 166 | var response = new LoginSuccess(); 167 | response.Message = "Login Successful"; 168 | response.Name = user; 169 | 170 | return response; 171 | } 172 | else 173 | { 174 | 175 | //Return an object back to the client 176 | 177 | var response = new LoginFailure(); 178 | response.Message = "Login Failed"; 179 | 180 | return response; 181 | } 182 | }) 183 | .Execute(); 184 | 185 | ``` 186 | 187 | ## Specifying client to send to 188 | 189 | When multiple clients are connected, it is possible to specify which client to send a message to using the "To" function. You can specify multiple clients in the "To" function. 190 | 191 | ```csharp 192 | server.Send(anObjectToSend) 193 | .To(client1,client2, ... ClientN) 194 | .Execute(); 195 | ``` 196 | ### Send to all clients 197 | 198 | You can send to all clients using the following. 199 | 200 | ```csharp 201 | 202 | //Send to all clients 203 | server.Send(anObjectToSend) 204 | .ToAll() 205 | .Execute(); 206 | 207 | //Note that you don't actually need to specify ToAll anymore. By default the API will send to all 208 | 209 | ``` 210 | 211 | ### Send to all clients except given clients 212 | You can also send to all clients and specify who to exclude: 213 | 214 | ```csharp 215 | 216 | //Send to all clients except client 3 217 | server.Send(anObjectToSend) 218 | .ToAllExcept(client3) //Can exclude more eg: .ToAllExcept(client3,client2, ... clientN) 219 | .Execute(); 220 | 221 | ``` 222 | 223 | ## OnConnect / OnDisconnet handles 224 | 225 | You can specify what should happen when someone connects or disconnects: 226 | 227 | ```csharp 228 | 229 | //Setup onconnect handler 230 | transport.OnClientConnect(c => Console.WriteLine("A client has connected with ip {0}",c.IPAddress)); 231 | 232 | //Setup onDisconnect handler 233 | transport.OnClientDisconnect(c=> Console.WriteLine("A client has disconnected with ip {0}",c.IPAddress)); 234 | 235 | ``` 236 | 237 | ## Sending object reliably 238 | 239 | When sending objects over UDP, the message is sent without reliability. You can switch reliably on for UDP on with the following: 240 | 241 | ```csharp 242 | client.SetReliable(); 243 | ``` 244 | 245 | After executing the above line, all objects that are sent will be sent reliably. 246 | 247 | Another option is to send only a specific message reliably. The following demonstrates this: 248 | 249 | ```csharp 250 | 251 | client.Send(anObjectToSend) 252 | .Reliable(); 253 | .Execute(); 254 | ``` 255 | 256 | ## Disconnect Client 257 | 258 | To disconnect one ore more clients from the server, you can use the DisconnectClient function: 259 | 260 | ```csharp 261 | 262 | server.DisconnectClient(client1,client2, ... clientN); 263 | 264 | ``` 265 | --------------------------------------------------------------------------------