/// <summary> /// Remove a connection specific shutdown delegate. /// </summary> /// <param name="handlerToRemove">The delegate to remove for shutdown events</param> public void RemoveShutdownHandler(NetworkComms.ConnectionEstablishShutdownDelegate handlerToRemove) { lock (_syncRoot) { ConnectionSpecificShutdownDelegate -= handlerToRemove; if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Debug("Removed ConnectionSpecificShutdownDelegate to connection with " + ConnectionInfo); } if (ConnectionSpecificShutdownDelegate == null) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Info("No handlers remain for ConnectionSpecificShutdownDelegate with " + ConnectionInfo); } } else { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Info("Handlers remain for ConnectionSpecificShutdownDelegate with " + ConnectionInfo); } } } }
/// <summary> /// Send an object using the provided <see cref="SendReceiveOptions"/> and wait for a returned object using provided <see cref="SendReceiveOptions"/>. /// </summary> /// <typeparam name="returnObjectType">The type of return object</typeparam> /// <param name="sendingPacketTypeStr">The sending packet type</param> /// <param name="expectedReturnPacketTypeStr">The packet type which will be used for the reply</param> /// <param name="returnPacketTimeOutMilliSeconds">A timeout in milliseconds after which if not reply is received will throw an ExpectedReturnTimeoutException.</param> /// <param name="sendObject">The object to send</param> /// <param name="sendOptions">SendReceiveOptions to use when sending</param> /// <param name="receiveOptions">SendReceiveOptions used when receiving the return object</param> /// <param name="sentPacketSequenceNumber">The sequence number of the packet sent</param> /// <returns>The requested return object</returns> public returnObjectType SendReceiveObject <returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, object sendObject, SendReceiveOptions sendOptions, SendReceiveOptions receiveOptions, out long sentPacketSequenceNumber) { returnObjectType returnObject = default(returnObjectType); bool remotePeerDisconnectedDuringWait = false; AutoResetEvent returnWaitSignal = new AutoResetEvent(false); #region SendReceiveDelegate NetworkComms.PacketHandlerCallBackDelegate <returnObjectType> SendReceiveDelegate = (packetHeader, sourceConnection, incomingObject) => { returnObject = incomingObject; returnWaitSignal.Set(); }; //We use the following delegate to quickly force a response timeout if the remote end disconnects NetworkComms.ConnectionEstablishShutdownDelegate SendReceiveShutDownDelegate = (sourceConnection) => { remotePeerDisconnectedDuringWait = true; returnObject = default(returnObjectType); returnWaitSignal.Set(); }; #endregion if (sendOptions == null) { sendOptions = ConnectionDefaultSendReceiveOptions; } if (receiveOptions == null) { receiveOptions = ConnectionDefaultSendReceiveOptions; } AppendShutdownHandler(SendReceiveShutDownDelegate); AppendIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate, receiveOptions); using (Packet sendPacket = new Packet(sendingPacketTypeStr, expectedReturnPacketTypeStr, sendObject, sendOptions)) SendPacket(sendPacket, out sentPacketSequenceNumber); //We wait for the return data here if (!returnWaitSignal.WaitOne(returnPacketTimeOutMilliSeconds)) { RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate); throw new ExpectedReturnTimeoutException("Timeout occurred after " + returnPacketTimeOutMilliSeconds.ToString() + "ms waiting for response packet of type '" + expectedReturnPacketTypeStr + "'."); } RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate); RemoveShutdownHandler(SendReceiveShutDownDelegate); if (remotePeerDisconnectedDuringWait) { throw new ExpectedReturnTimeoutException("Remote end closed connection before data was successfully returned."); } else { return(returnObject); } }
public override void InitializePacket() { closeHandler = new NetworkComms.ConnectionEstablishShutdownDelegate((Connection connection) => { mainWindow.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() => { mainWindow.ConnectionClosedLogOut(); })); }); Open(); }
/// <summary> /// Add a connection specific shutdown delegate /// </summary> /// <param name="handlerToAppend">The delegate to call when a connection is shutdown</param> public void AppendShutdownHandler(NetworkComms.ConnectionEstablishShutdownDelegate handlerToAppend) { lock (_syncRoot) { if (ConnectionSpecificShutdownDelegate == null) { ConnectionSpecificShutdownDelegate = handlerToAppend; } else { ConnectionSpecificShutdownDelegate += handlerToAppend; } if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Debug("Added a connection specific shutdown delegate to connection with " + ConnectionInfo); } } }
/// <summary> /// Send the provided packet to the remoteEndPoint. Waits for receive confirmation if required. /// </summary> /// <param name="packet">The packet to send</param> /// <param name="packetSequenceNumber">The sequence number of the packet sent</param> internal void SendPacket(Packet packet, out long packetSequenceNumber) { if (NetworkComms.LoggingEnabled) { string packetDataMD5 = ""; if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.CheckSumHash)) { packetDataMD5 = packet.PacketHeader.GetOption(PacketHeaderStringItems.CheckSumHash); } NetworkComms.Logger.Trace("Entering packet send of '" + packet.PacketHeader.PacketType + "' packetType to " + ConnectionInfo + (packetDataMD5 == "" ? "" : ". PacketCheckSum=" + packetDataMD5)); } //Multiple threads may try to send packets at the same time so wait one at a time here lock (sendLocker) { //We don't allow sends on a closed connection if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) { throw new CommunicationException("Attempting to send packet on connection which has been closed or is currently closing."); } //Set packet sequence number inside sendLocker //Increment the global counter as well to ensure future connections with the same host can not create duplicates Interlocked.Increment(ref NetworkComms.totalPacketSendCount); packetSequenceNumber = packetSequenceCounter++; packet.PacketHeader.SetOption(PacketHeaderLongItems.PacketSequenceNumber, packetSequenceNumber); string confirmationCheckSum = ""; AutoResetEvent confirmationWaitSignal = new AutoResetEvent(false); bool remotePeerDisconnectedDuringWait = false; #region Delegates //Specify a delegate we may use if we require receive confirmation NetworkComms.PacketHandlerCallBackDelegate <string> confirmationDelegate = (packetHeader, connectionInfo, incomingString) => { //if (connectionInfo.NetworkIdentifier == this.ConnectionInfo.NetworkIdentifier && connectionInfo.RemoteEndPoint == this.ConnectionInfo.RemoteEndPoint) //{ confirmationCheckSum = incomingString; confirmationWaitSignal.Set(); //} }; //We use the following delegate to quickly force a response timeout if the remote end disconnects during a send/wait NetworkComms.ConnectionEstablishShutdownDelegate ConfirmationShutDownDelegate = (connectionInfo) => { //if (connectionInfo.NetworkIdentifier == this.ConnectionInfo.NetworkIdentifier && connectionInfo.RemoteEndPoint == this.ConnectionInfo.RemoteEndPoint) //{ remotePeerDisconnectedDuringWait = true; confirmationWaitSignal.Set(); //} }; #endregion try { #region Prepare For Confirmation and Possible Validation //Add the confirmation handler if required if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired)) { AppendIncomingPacketHandler(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Confirmation), confirmationDelegate, NetworkComms.InternalFixedSendReceiveOptions); AppendShutdownHandler(ConfirmationShutDownDelegate); } //If this packet is not a checkSumFailResend if (NetworkComms.EnablePacketCheckSumValidation && packet.PacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.CheckSumFailResend)) { //We only want to keep packets when they are under some provided theshold //otherwise this becomes a quick 'memory leak' if (packet.PacketData.Length < NetworkComms.CheckSumMismatchSentPacketCacheMaxByteLimit) { lock (sentPacketsLocker) { var hash = packet.PacketHeader.GetOption(PacketHeaderStringItems.CheckSumHash); if (!sentPackets.ContainsKey(hash)) { sentPackets.Add(hash, new SentPacket(packet)); } } } } #endregion SendPacketSpecific(packet); #region SentPackets Cleanup //If sent packets is greater than 40 we delete anything older than a minute lock (sentPacketsLocker) { if ((DateTime.Now - NetworkComms.LastSentPacketCacheCleanup).TotalMinutes > NetworkComms.MinimumSentPacketCacheTimeMinutes / 2) { Dictionary <string, SentPacket> newSentPackets = new Dictionary <string, SentPacket>(); DateTime thresholdTime = DateTime.Now.AddMinutes(-NetworkComms.MinimumSentPacketCacheTimeMinutes); foreach (var storedPacket in sentPackets) { if (storedPacket.Value.SentPacketCreationTime >= thresholdTime) { newSentPackets.Add(storedPacket.Key, storedPacket.Value); } } sentPackets = newSentPackets; NetworkComms.LastSentPacketCacheCleanup = DateTime.Now; } } #endregion #region Wait For Confirmation If Required //If we required receive confirmation we now wait for that confirmation if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired)) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... waiting for receive confirmation packet."); } if (!(confirmationWaitSignal.WaitOne(NetworkComms.PacketConfirmationTimeoutMS))) { throw new ConfirmationTimeoutException("Confirmation packet timeout."); } if (remotePeerDisconnectedDuringWait) { throw new ConfirmationTimeoutException("Remote end closed connection before confirmation packet was returned."); } else { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... confirmation packet received."); } } } #endregion //Update the traffic time as late as possible incase there is a problem ConnectionInfo.UpdateLastTrafficTime(); } catch (ConfirmationTimeoutException) { //Confirmation timeout there is no need to close the connection as this //does not neccessarily mean there is a conneciton problem throw; } catch (CommunicationException) { //We close the connection due to communication exceptions CloseConnection(true, 47); throw; } catch (TimeoutException ex) { //We close the connection due to communication exceptions if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Warn("Timeout exception for connection " + this.ConnectionInfo + (ex.Message != null ? ". " + ex.Message : ".")); } CloseConnection(true, 48); throw new ConnectionSendTimeoutException(ex.ToString()); } catch (Exception ex) { //We close the connection due to communication exceptions CloseConnection(true, 49); throw new CommunicationException(ex.ToString()); } finally { if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired)) { //Cleanup our delegates RemoveIncomingPacketHandler(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Confirmation), confirmationDelegate); RemoveShutdownHandler(ConfirmationShutDownDelegate); } } } if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace("Completed packet send of '" + packet.PacketHeader.PacketType + "' packetType to " + ConnectionInfo); } }
/// <summary> /// Send an object using the provided <see cref="SendReceiveOptions"/> and wait for a returned object using provided /// <see cref="SendReceiveOptions"/>. /// </summary> /// <typeparam name="sendObjectType">The sending object type, i.e. string, int[], etc</typeparam> /// <typeparam name="returnObjectType">The type of return object</typeparam> /// <param name="sendingPacketTypeStr">The sending packet type</param> /// <param name="expectedReturnPacketTypeStr">The packet type which will be used for the reply</param> /// <param name="returnPacketTimeOutMilliSeconds">A timeout in milliseconds after which if not reply is received will /// throw an ExpectedReturnTimeoutException.</param> /// <param name="sendObject">The object to send</param> /// <param name="sendOptions">SendReceiveOptions to use when sending</param> /// <param name="receiveOptions">SendReceiveOptions used when receiving the return object</param> /// <param name="sentPacketSequenceNumber">The sequence number of the packet sent</param> /// <returns>The requested return object</returns> public returnObjectType SendReceiveObject <sendObjectType, returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, sendObjectType sendObject, SendReceiveOptions sendOptions, SendReceiveOptions receiveOptions, out long sentPacketSequenceNumber) { if (sendingPacketTypeStr == expectedReturnPacketTypeStr) { throw new ArgumentException("The provided sendingPacketTypeStr and expectedReturnPacketTypeStr parameters must be different."); } returnObjectType returnObject = default(returnObjectType); bool remotePeerDisconnectedDuringWait = false; AutoResetEvent returnWaitSignal = new AutoResetEvent(false); #region SendReceiveDelegate NetworkComms.PacketHandlerCallBackDelegate <returnObjectType> SendReceiveDelegate = (packetHeader, sourceConnection, incomingObject) => { returnObject = incomingObject; returnWaitSignal.Set(); }; //We use the following delegate to quickly force a response timeout if the remote end disconnects NetworkComms.ConnectionEstablishShutdownDelegate SendReceiveShutDownDelegate = (sourceConnection) => { remotePeerDisconnectedDuringWait = true; returnObject = default(returnObjectType); returnWaitSignal.Set(); }; #endregion if (sendOptions == null) { sendOptions = ConnectionDefaultSendReceiveOptions; } if (receiveOptions == null) { receiveOptions = ConnectionDefaultSendReceiveOptions; } AppendShutdownHandler(SendReceiveShutDownDelegate); AppendIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate, receiveOptions); //Check to see if we already have a packet Packet sendObjectAsPacket = sendObject as Packet; if (sendObjectAsPacket == null) { using (Packet sendPacket = new Packet(sendingPacketTypeStr, expectedReturnPacketTypeStr, sendObject, sendOptions)) SendPacket <sendObjectType>(sendPacket, out sentPacketSequenceNumber); } else { if (sendObjectAsPacket.PacketHeader.PacketType != sendingPacketTypeStr) { throw new ArgumentException("Unable to send object of type Packet if the PacketHeader.PacketType and sendingPacketType do not match."); } SendPacket <sendObjectType>(sendObjectAsPacket, out sentPacketSequenceNumber); } //We wait for the return data here #if NET2 if (!returnWaitSignal.WaitOne(returnPacketTimeOutMilliSeconds, false)) #else if (!returnWaitSignal.WaitOne(returnPacketTimeOutMilliSeconds)) #endif { RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate); throw new ExpectedReturnTimeoutException("Timeout occurred after " + returnPacketTimeOutMilliSeconds.ToString() + "ms waiting for response packet of type '" + expectedReturnPacketTypeStr + "'."); } RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate); RemoveShutdownHandler(SendReceiveShutDownDelegate); if (remotePeerDisconnectedDuringWait) { throw new ConnectionShutdownException("Remote end closed connection before data was successfully returned."); } else { return(returnObject); } }
/// <summary> /// Run example /// </summary> public static void RunExample() { //Select mode Console.WriteLine("SpeedTest Example ...\n"); Console.WriteLine("Please select host or peer mode:"); Console.WriteLine("1 - Host Mode (Catches Data)"); Console.WriteLine("2 - Peer Mode (Sends Data)"); //Read in user choice if (Console.ReadKey(true).Key == ConsoleKey.D1) { hostMode = true; } else { hostMode = false; } if (hostMode) { //Prepare DFS in host mode #region ServerMode Console.WriteLine("\n ... host mode selected."); NetworkComms.ConnectionEstablishShutdownDelegate clientEstablishDelegate = (connection) => { Console.WriteLine("Client " + connection.ConnectionInfo + " connected."); }; NetworkComms.ConnectionEstablishShutdownDelegate clientShutdownDelegate = (connection) => { Console.WriteLine("Client " + connection.ConnectionInfo + " disconnected."); }; NetworkComms.PacketHandlerCallBackDelegate <byte[]> IncomingDataDelegate = (packetHeader, connection, incomingObject) => { Console.WriteLine("Speed bytes received from " + connection.ConnectionInfo + "."); }; NetworkComms.AppendGlobalConnectionEstablishHandler(clientEstablishDelegate); NetworkComms.AppendGlobalConnectionCloseHandler(clientShutdownDelegate); NetworkComms.AppendGlobalIncomingPacketHandler("SpeedData", IncomingDataDelegate); //Start listening for TCP connections //We want to select a random port on all available adaptors so provide //an IPEndPoint using IPAddress.Any and port 0. Connection.StartListening(ConnectionType.TCP, new IPEndPoint(IPAddress.Any, 0)); Console.WriteLine("\nListening for incoming connections on:"); foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP)) { Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port); } Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier); Console.WriteLine("\nPress 'q' to close host.\n"); while (true) { ConsoleKeyInfo pressedKey = Console.ReadKey(true); if (pressedKey.Modifiers != ConsoleModifiers.Control && pressedKey.Key == ConsoleKey.Q) { Console.WriteLine("Closing host."); break; } } #endregion } else if (!hostMode) { //Prepare DFS in peer mode #region PeerMode Console.WriteLine("\n ... peer mode selected."); Console.WriteLine("\nPlease enter how large the test data packet should be in MB and press return (larger is more accurate), e.g. 1024:"); int numberMegsToCreate = int.Parse(Console.ReadLine()); //Fill a byte[] with random data DateTime startTime = DateTime.Now; Random randGen = new Random(); byte[] someRandomData = new byte[numberMegsToCreate * 1024 * 1024]; randGen.NextBytes(someRandomData); Console.WriteLine("\nTest speed data created. Using {0}MB.\n", numberMegsToCreate); NetworkComms.PacketConfirmationTimeoutMS = 20000; ConnectionInfo serverConnectionInfo = ExampleHelper.GetServerDetails(); Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier); SendReceiveOptions nullCompressionSRO = new SendReceiveOptions <NullSerializer>(); //Add options which will require receive confirmations and also include packet construction time //in the packet header. nullCompressionSRO.Options.Add("ReceiveConfirmationRequired", ""); nullCompressionSRO.Options.Add("IncludePacketConstructionTime", ""); TCPConnection serverConnection = TCPConnection.GetConnection(serverConnectionInfo); Stopwatch timer = new Stopwatch(); while (true) { timer.Reset(); timer.Start(); serverConnection.SendObject("SpeedData", someRandomData, nullCompressionSRO); timer.Stop(); Console.WriteLine("SpeedData sent successfully with receive confirmation in {0}secs. Corresponds to {1}MB/s", (timer.ElapsedMilliseconds / 1000.0).ToString("0.00"), (numberMegsToCreate / (timer.ElapsedMilliseconds / 1000.0)).ToString("0.00")); } #endregion } NetworkComms.Shutdown(); }
/// <summary> /// The distributed file system (DFS) allows for the high performance distribution of large files /// within a cluster of peers. This sytem replicates the behaviour the bitTorrent protocol by using /// NetworkCommsDotNet. This example demonstrates the DFS in action. /// </summary> public static void RunExample() { //Select launch mode Console.WriteLine("Launching DFS system ...\n"); Console.WriteLine("Please select host or peer mode:"); Console.WriteLine("1 - Host Mode (Original source of data)"); Console.WriteLine("2 - Peer Mode (Builds data and then acts as subhost)"); //Read in user choice //if (Console.ReadKey(true).Key == ConsoleKey.D1) hostMode = true; //else hostMode = false; hostMode = false; if (hostMode) { //Prepare DFS in host mode #region ServerMode Console.WriteLine("\n ... host mode selected."); Console.WriteLine("\nPlease enter how large the test data packet should be in MB and press return, e.g. 50:"); int numberMegsToCreate = int.Parse(Console.ReadLine()); //Fill a byte[] with random data DateTime startTime = DateTime.Now; Random randGen = new Random(); byte[] someRandomData = new byte[numberMegsToCreate * 1024 * 1024]; randGen.NextBytes(someRandomData); Console.WriteLine("\n ... successfully created a {0}MB test packet.", ((double)someRandomData.Length / (1024.0 * 1024.0)).ToString("0.###")); object listLocker = new object(); List <IPEndPoint> connectedClients = new List <IPEndPoint>(); //Initialise the DFS before creating the test object to ensure the correct port and IP are used as the seed DFS.Initialise(10000); //Create the item to be distributed List <ConnectionInfo> seedConnectionInfoList = (from current in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP) select new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, current, true)).ToList(); DistributedItem newItem = new DistributedItem("exampleItem", "example1", new MemoryStream(someRandomData), seedConnectionInfoList, DataBuildMode.Memory_Single); NetworkComms.ConnectionEstablishShutdownDelegate clientEstablishDelegate = (connection) => { lock (listLocker) connectedClients.Remove((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint); Console.WriteLine("Client " + connection.ConnectionInfo + " connected."); }; NetworkComms.ConnectionEstablishShutdownDelegate clientShutdownDelegate = (connection) => { lock (listLocker) connectedClients.Remove((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint); Console.WriteLine("Client " + connection.ConnectionInfo + " disconnected."); }; NetworkComms.PacketHandlerCallBackDelegate <int> ReplyDelegate = (packetHeader, connection, incomingObject) => { //Push the item into the swarm lock (listLocker) if (!connectedClients.Contains(connection.ConnectionInfo.RemoteEndPoint)) { connectedClients.Add((IPEndPoint)connection.ConnectionInfo.RemoteEndPoint); } DFS.PushItemToPeer(connection, newItem, "BigDataRequestResponse"); Console.WriteLine("Pushing item to " + connection.ConnectionInfo + " (" + connection.ConnectionInfo.NetworkIdentifier + "). {0} in swarm. P#={1}, S#={2}.", connectedClients.Count, newItem.PushCount, newItem.TotalChunkSupplyCount); }; NetworkComms.PacketHandlerCallBackDelegate <string> InfoDelegate = (packetHeader, connectionId, incomingString) => { Console.WriteLine(" ... " + connectionId + " - " + incomingString); }; Console.WriteLine(" ... DFS has been initialised."); NetworkComms.AppendGlobalConnectionEstablishHandler(clientEstablishDelegate); NetworkComms.AppendGlobalConnectionCloseHandler(clientShutdownDelegate); NetworkComms.AppendGlobalIncomingPacketHandler("BigDataRequest", ReplyDelegate); NetworkComms.AppendGlobalIncomingPacketHandler("ClientInfo", InfoDelegate); Console.WriteLine("\nListening for incoming connections on:"); foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP)) { Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port); } Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier); Console.WriteLine("\nPress 's' to write out stats, 'q' to close any connected peers, 'ctrl+q' to close this host.\n"); while (true) { ConsoleKeyInfo pressedKey = Console.ReadKey(true); #region Host Shutdown if (pressedKey.Modifiers != ConsoleModifiers.Control && pressedKey.Key == ConsoleKey.Q) { Console.WriteLine("Sending shutdown to clients..."); lock (listLocker) { for (int i = 0; i < connectedClients.Count; i++) { try { TCPConnection.GetConnection(new ConnectionInfo(connectedClients[i])).SendObject("ClientCommand", 0); } catch (Exception) { Console.WriteLine("Exception telling client to shutdown. Probably already disconnected."); } } } } else if (pressedKey.Modifiers == ConsoleModifiers.Control && pressedKey.Key == ConsoleKey.Q) { Console.WriteLine("Sending shutdown to clients and closing local host..."); lock (listLocker) { for (int i = 0; i < connectedClients.Count; i++) { try { TCPConnection.GetConnection(new ConnectionInfo(connectedClients[i])).SendObject("ClientCommand", 0); } catch (Exception) { Console.WriteLine("Exception telling client to shutdown. Probably already disconnected."); } } } Console.WriteLine("Closing host."); break; } else if (pressedKey.Key == ConsoleKey.S) { #region Stats Console.WriteLine("\nCurrent Stats:"); Console.WriteLine("{0} comms connections.", NetworkComms.TotalNumConnections()); if (NetworkComms.TotalNumConnections() > 0) { Console.WriteLine("Connections with: "); var connections = NetworkComms.GetExistingConnection(); foreach (var connection in connections) { Console.WriteLine("\t{0}", connection.ConnectionInfo); } } #endregion } #endregion } #endregion } else if (!hostMode) { //Prepare DFS in peer mode #region PeerMode Console.WriteLine("\n ... peer mode selected."); try { ConnectionInfo serverConnectionInfo = new ConnectionInfo("192.168.0.105", 10000); //ExampleHelper.GetServerDetails(out serverConnectionInfo); DFS.Initialise(10000); Console.WriteLine(" ... DFS has been initialised."); bool shutDown = false; bool buildComplete = true; DateTime startTime = DateTime.Now; int buildCount = 0; NetworkComms.PacketHandlerCallBackDelegate <byte[]> ReplyDelegate = (packetHeader, connection, dataBytes) => { try { buildCount++; DistributedItem item = DFS.MostRecentlyCompletedItem(); Console.WriteLine(" ... full item build " + buildCount + " took {0} secs ({1} MB/s) using {2} total peers. {3} builds completed.", (DateTime.Now - startTime).TotalSeconds.ToString("0.00"), (((double)dataBytes.Length / 1048576.0) / (DateTime.Now - startTime).TotalSeconds).ToString("0.0"), item.SwarmChunkAvailability.NumPeersInSwarm(), buildCount); double speed = (((double)dataBytes.Length / 1048576.0) / (DateTime.Now - startTime).TotalSeconds); connection.SendObject("ClientInfo", " ... build " + buildCount + " took " + (DateTime.Now - startTime).TotalSeconds.ToString("0.00") + " secs (" + speed.ToString("0.0") + " MB/s) using " + item.SwarmChunkAvailability.NumPeersInSwarm() + " peers. " + buildCount + " builds completed."); buildComplete = true; dataBytes = null; GC.Collect(); } catch (Exception ex) { LogTools.LogException(ex, "DFSTestCallbackError"); Console.WriteLine("Shutting down due to exception."); shutDown = true; } }; NetworkComms.PacketHandlerCallBackDelegate <int> ShutdownDelegate = (packetHeader, connectionId, packetDataBytes) => { shutDown = true; }; NetworkComms.AppendGlobalIncomingPacketHandler("BigDataRequestResponse", ReplyDelegate); NetworkComms.AppendGlobalIncomingPacketHandler("ClientCommand", ShutdownDelegate); Console.WriteLine("\nIdentifier - {0}", NetworkComms.NetworkIdentifier); Console.WriteLine("\nListening for incoming objects on:"); foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP)) { Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port); } startTime = DateTime.Now; //while (true) //{ if (!shutDown && buildComplete) { //Console.WriteLine("\nPress 'r' to rebuild or any other key to shutdown."); //var shutdownKey = Console.ReadKey(true).Key; //if (shutdownKey != ConsoleKey.R) shutDown = true; //if (!shutDown) //{ DistributedItem item = DFS.MostRecentlyCompletedItem(); if (item != null) { DFS.RemoveItem(item.Data.CompleteDataCheckSum); Console.WriteLine("\n ... item removed from local and rebuilding at {0}.", DateTime.Now.ToString("HH:mm:ss.fff")); startTime = DateTime.Now; } buildComplete = false; TCPConnection.GetConnection(serverConnectionInfo).SendObject("BigDataRequest"); Console.WriteLine(" ... initiating item build ..."); //} } else if (shutDown) { shutDown = true; DFS.Shutdown(); //break; } Thread.Sleep(250); //} while (!buildComplete) { Thread.Sleep(250); } try { TCPConnection.GetConnection(serverConnectionInfo).SendObject("ClientInfo", "... shutting down, initiating DFS shutdown."); } catch (CommsException) { Console.WriteLine("... unable to inform local of shutdown. Connection probably already closed."); } Console.WriteLine("Done. Completed {0} builds.", buildCount); } catch (Exception ex) { Console.WriteLine("Bad Error!"); LogTools.LogException(ex, "DFSTestError_" + NetworkComms.NetworkIdentifier); } #endregion } DFS.Shutdown(); NetworkComms.Shutdown(); }