/// <summary> /// Defines the entry point of the application. /// </summary> /// <param name="args">Command line arguments</param> public static void Main(string[] args) { Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); if (args == null || args.Length < 1) { Trace.TraceError("USAGE: SecureTransportClientTool.exe <connection string> [<request length>]"); return; } string connectionString = args[0]; int requestLength = 128; int waitTimeoutMs = 30000; if (args.Length > 1) { requestLength = int.Parse(args[1]); } var path = System.Reflection.Assembly.GetExecutingAssembly().Location; var builder = new ConfigurationBuilder().SetBasePath(Path.GetDirectoryName(path)).AddJsonFile("appSettings.json"); var appSettings = builder.Build(); var configuration = new SecureTransport.Configuration(); int maxConcurrentRequests = int.Parse(appSettings["MaxConcurrentRequests"]); configuration.SendBufferSize = int.Parse(appSettings["SendBufferSize"]); configuration.ReceiveBufferSize = int.Parse(appSettings["ReceiveBufferSize"]); configuration.UseSecureConnection = bool.Parse(appSettings["SSL.UseSSL"]); if (configuration.UseSecureConnection) { string[] clientThumbprints = appSettings["SSL.ClientCerts"].Split(new char[] { ';', ',' }); string[] serviceThumbprints = appSettings["SSL.ServerCerts"].Split(new char[] { ';', ',' }); configuration.ClientCertificates = SecureTransport.GetCertificatesFromThumbPrintOrFileName(clientThumbprints); configuration.ServerCertificates = SecureTransport.GetCertificatesFromThumbPrintOrFileName(serviceThumbprints); } Trace.TraceInformation( "Connecting to {0}. Using SSL={1} RequestLength={2} MaxConcurrentRequests={3}, SendBufferSize={4}, ReceiveBufferSize={5}", connectionString, configuration.UseSecureConnection, requestLength, maxConcurrentRequests, configuration.SendBufferSize, configuration.ReceiveBufferSize); var connectionAvailable = new ManualResetEvent(false); IPEndPoint[] endpoints = SecureTransport.ParseConnectionString(connectionString); using (var transport = new SecureTransport(configuration)) { transport.StartClient(endpoints); Console.CancelKeyPress += (sender, eventArgs) => { Trace.TraceInformation("Attempting to close client transport"); transport.Close(); }; IConnection currentConnection = null; transport.OnNewConnection = connection => { currentConnection = connection; connectionAvailable.Set(); }; transport.OnConnectionLost = () => { connectionAvailable.Reset(); }; var random = new Random(); var timer = new Stopwatch(); timer.Start(); long requestsSent = 0; byte[] request = new byte[requestLength]; random.NextBytes(request); var sendSemaphore = new SemaphoreSlim(maxConcurrentRequests, maxConcurrentRequests); while (true) { if (!connectionAvailable.WaitOne(waitTimeoutMs)) { Trace.TraceWarning("Connection is not available. retrying..."); continue; } currentConnection.OnPacketReceived = packet => { }; try { if (!sendSemaphore.Wait(waitTimeoutMs)) { Trace.TraceError("Timedout waiting for send semaphore..."); continue; } currentConnection.SendAsync(request).ContinueWith(_ => sendSemaphore.Release()); } catch (IOException ex) { Trace.TraceError("IO Exception: {0}", ex.Message); } Interlocked.Increment(ref requestsSent); if (timer.ElapsedMilliseconds > 5000) { long rate = (requestsSent * 1000) / timer.ElapsedMilliseconds; int inflightCount = maxConcurrentRequests - sendSemaphore.CurrentCount; Trace.TraceInformation($"Send rate={rate} InFlight={inflightCount}"); requestsSent = 0; timer.Restart(); } } } }
private static void SecureTransportInternal(Action <string> log, string testCaseName, int numberOfClients) { var packetCount = 0; log($"Starting {testCaseName} ..."); SecureTransport server = null; SecureTransport[] clients = new SecureTransport[0]; try { // Start the service server = new SecureTransport(new SecureTransport.Configuration { UseSecureConnection = false, IsClientCertificateRequired = false, CommunicationProtocolVersion = RingMasterCommunicationProtocol.MaximumSupportedVersion, }); var serverSendTask = Task.CompletedTask; server.OnNewConnection = connection => { connection.OnPacketReceived = packet => { Interlocked.Increment(ref packetCount); serverSendTask.GetAwaiter().GetResult(); serverSendTask = connection.SendAsync(packet); }; Trace.TraceInformation("Server accepted a new connection: {0}", connection.RemoteIdentity); }; server.StartServer(Port); // Start the client clients = Enumerable.Range(0, numberOfClients).Select( _ => new SecureTransport(new SecureTransport.Configuration { UseSecureConnection = false, IsClientCertificateRequired = false, CommunicationProtocolVersion = RingMasterCommunicationProtocol.MaximumSupportedVersion, })) .ToArray(); Parallel.ForEach( clients, client => client.OnNewConnection = connection => { var clientSendTask = Task.CompletedTask; connection.OnPacketReceived = packet => { clientSendTask.GetAwaiter().GetResult(); clientSendTask = connection.SendAsync(packet); }; clientSendTask = connection.SendAsync(new byte[PacketLength]); }); Parallel.ForEach( clients, client => client.StartClient(new IPEndPoint(IPAddress.Loopback, Port))); log($" Warming up for {WarmupMilliSeconds / 1000} seconds"); Thread.Sleep(WarmupMilliSeconds); log($" Start measuring for {MeasureMilliSeconds} seconds"); var sw = new Stopwatch(); int gen0 = GC.CollectionCount(0), gen1 = GC.CollectionCount(1), gen2 = GC.CollectionCount(2); sw.Start(); Interlocked.Exchange(ref packetCount, 0); for (int i = 0; i < MeasureMilliSeconds / PrintStatusInterval; i++) { Thread.Sleep(PrintStatusInterval); log($" {DateTime.Now.ToString()} count={packetCount}"); } sw.Stop(); var totalCount = packetCount; var rate = totalCount / sw.Elapsed.TotalSeconds; Parallel.ForEach(clients, client => client.Close()); server.Close(); log($"{testCaseName}: {totalCount} in {sw.Elapsed} with {numberOfClients} clients. QPS={rate}"); log($" Gen0={GC.CollectionCount(0) - gen0} Gen1={GC.CollectionCount(1) - gen1} Gen2={GC.CollectionCount(2) - gen2}\n"); log(string.Empty); } finally { server?.Dispose(); Parallel.ForEach(clients, client => client.Dispose()); } }
/// <summary> /// Defines the entry point of the application. /// </summary> /// <param name="args">Command line arguments</param> public static void Main(string[] args) { Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); if (args == null || args.Length < 1) { Trace.TraceError("USAGE: SecureTransportServiceTool.exe <port>"); return; } int port = int.Parse(args[0]); var configuration = new SecureTransport.Configuration(); var path = System.Reflection.Assembly.GetExecutingAssembly().Location; var builder = new ConfigurationBuilder().SetBasePath(Path.GetDirectoryName(path)).AddJsonFile("appSettings.json"); IConfiguration appSettings = builder.Build(); int maxConcurrentRequests = int.Parse(appSettings["MaxConcurrentRequests"]); configuration.UseSecureConnection = bool.Parse(appSettings["SSL.UseSSL"]); configuration.SendBufferSize = int.Parse(appSettings["SendBufferSize"]); configuration.ReceiveBufferSize = int.Parse(appSettings["ReceiveBufferSize"]); if (configuration.UseSecureConnection) { string[] clientThumbprints = appSettings["SSL.ClientCerts"].Split(new char[] { ';', ',' }); string[] serviceThumbprints = appSettings["SSL.ServerCerts"].Split(new char[] { ';', ',' }); configuration.ClientCertificates = SecureTransport.GetCertificatesFromThumbPrintOrFileName(clientThumbprints); configuration.ServerCertificates = SecureTransport.GetCertificatesFromThumbPrintOrFileName(serviceThumbprints); } Trace.TraceInformation( "Listening on port {0}. Using SSL={1}, MaxConcurentRequests={2}, SendBufferSize={3}, ReceiveBufferSize={4}", port, configuration.UseSecureConnection, maxConcurrentRequests, configuration.SendBufferSize, configuration.ReceiveBufferSize); using (var transport = new SecureTransport(configuration)) { var timer = Stopwatch.StartNew(); long activeConnections = 0; long packetsReceived = 0; Task serverTask = transport.StartServer(port); Console.CancelKeyPress += (sender, eventArgs) => { Trace.TraceInformation("Attempting to close server transport"); transport.Close(); }; var semaphore = new SemaphoreSlim(maxConcurrentRequests, maxConcurrentRequests); transport.OnNewConnection = connection => { Trace.TraceInformation("Connection Established with {0}", connection.RemoteEndPoint); Interlocked.Increment(ref activeConnections); connection.OnPacketReceived = packet => { semaphore.Wait(); Interlocked.Increment(ref packetsReceived); connection.SendAsync(packet).ContinueWith(_ => semaphore.Release()); }; connection.OnConnectionLost = () => { Trace.TraceInformation("Connection with {0} was lost", connection.RemoteEndPoint); Interlocked.Decrement(ref activeConnections); }; }; while (!serverTask.Wait(5000)) { timer.Stop(); long rate = (long)(packetsReceived * 1000) / timer.ElapsedMilliseconds; int inflightCount = maxConcurrentRequests - semaphore.CurrentCount; Trace.TraceInformation($"ActiveConnections={activeConnections}, RequestRate {rate} InFlight count={inflightCount}"); packetsReceived = 0; timer.Restart(); } } }