Skip to content

Commit

Permalink
Feature/performance tuning (cosullivan#66)
Browse files Browse the repository at this point in the history
* WIP

* removed the WithTimeout extension as it was leaking memory
  • Loading branch information
cosullivan authored May 28, 2018
1 parent f4c01c1 commit 89edf00
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 189 deletions.
4 changes: 3 additions & 1 deletion Src/SampleApp/Examples/SimpleExample.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading;
using System.Net;
using System.Threading;
using SmtpServer;

namespace SampleApp.Examples
Expand All @@ -12,6 +13,7 @@ public static void Run()
var options = new SmtpServerOptionsBuilder()
.ServerName("SmtpServer SampleApp")
.Port(9025)
//.Endpoint(new EndpointDefinitionBuilder().Endpoint(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9025)).Build())
.Build();

var server = new SmtpServer.SmtpServer(options);
Expand Down
260 changes: 122 additions & 138 deletions Src/SampleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using MimeKit;
using MimeKit.Text;
using SampleApp.Examples;
Expand All @@ -15,165 +21,143 @@ class Program
{
static void Main(string[] args)
{
//SimpleExample.Run();
//SessionTracingExample.Run();
//SessionContextExample.Run();
//SimpleServerExample.Run();
SecureServerExample.Run();
}

//var cancellationTokenSource = new CancellationTokenSource();

// var certificate = CreateCertificate();

// ServicePointManager.ServerCertificateValidationCallback = IgnoreCertificateValidationFailureForTestingOnly;

// var options = new OptionsBuilder()
// .ServerName("SmtpServer SampleApp")
// .Port(9025)
// .Certificate(certificate)
// .SupportedSslProtocols(SslProtocols.Default)
// .MessageStore(new SampleMessageStore())
// //.MailboxFilter(new SampleMailboxFilter())
// .UserAuthenticator(new SampleUserAuthenticator())
// .Build();

// var s = RunServerAsync(options, cancellationTokenSource.Token);
// var c = RunClientAsync("A", 1, false, cancellationTokenSource.Token);
// //var c = RunFolderAsync(@"C:\Dev\temp\", "msg.txt", CancellationToken.None);
// //var c = RunFileAsync(@"c:\dev\temp\msg.txt", CancellationToken.None);

// Console.WriteLine("Press any key to continue");
// Console.ReadKey();

// cancellationTokenSource.Cancel();

// s.WaitWithoutException();
// c.WaitWithoutException();

// return;

// if (args == null || args.Length == 0)
// {
// var serverTask = RunServerAsync(options, cancellationTokenSource.Token);
// var clientTask1 = RunClientAsync("A", cancellationToken: cancellationTokenSource.Token);
// var clientTask2 = RunClientAsync("B", cancellationToken: cancellationTokenSource.Token);
// var clientTask3 = RunClientAsync("C", cancellationToken: cancellationTokenSource.Token);

// Console.WriteLine("Press any key to continue");
// Console.ReadKey();

// cancellationTokenSource.Cancel();

// serverTask.WaitWithoutException();
// clientTask1.WaitWithoutException();
// clientTask2.WaitWithoutException();
// clientTask3.WaitWithoutException();

// return;
// }

// if (args[0] == "server")
// {
// var serverTask = RunServerAsync(options, cancellationTokenSource.Token);
var cancellationTokenSource = new CancellationTokenSource();

if (args == null || args.Length == 0)
{
var serverTask = RunServerAsync(cancellationTokenSource.Token);
var clientTask1 = RunClientAsync("A", forceConnection: false, cancellationToken: cancellationTokenSource.Token);
var clientTask2 = RunClientAsync("B", forceConnection: false, cancellationToken: cancellationTokenSource.Token);
var clientTask3 = RunClientAsync("C", forceConnection: false, cancellationToken: cancellationTokenSource.Token);

// Console.WriteLine("Press any key to continue");
// Console.ReadKey();
Console.WriteLine("Press any key to continue");
Console.ReadKey();

// cancellationTokenSource.Cancel();
cancellationTokenSource.Cancel();

// serverTask.WaitWithoutException();
serverTask.WaitWithoutException();
clientTask1.WaitWithoutException();
clientTask2.WaitWithoutException();
clientTask3.WaitWithoutException();

// return;
// }
return;
}

// if (args[0] == "client")
// {
// var clientTask = RunClientAsync(args[1], cancellationToken: cancellationTokenSource.Token);
if (args[0] == "server")
{
var serverTask = RunServerAsync(cancellationTokenSource.Token);

// Console.WriteLine("Press any key to continue");
// Console.ReadKey();
Console.WriteLine("Press any key to continue");
Console.ReadKey();

// cancellationTokenSource.Cancel();
cancellationTokenSource.Cancel();

// clientTask.WaitWithoutException();
// }
serverTask.WaitWithoutException();

// if (args[0] == "folder")
// {
// var clientTask = RunClientAsync(args[1], cancellationToken: cancellationTokenSource.Token);
return;
}

// Console.WriteLine("Press any key to continue");
// Console.ReadKey();
if (args[0] == "client")
{
var clientTask = RunClientAsync(args[1], cancellationToken: cancellationTokenSource.Token);

// cancellationTokenSource.Cancel();
Console.WriteLine("Press any key to continue");
Console.ReadKey();

// clientTask.WaitWithoutException();
// }
//}
cancellationTokenSource.Cancel();

//static async Task RunServerAsync(ISmtpServerOptions options, CancellationToken cancellationToken)
//{
// var smtpServer = new SmtpServer.SmtpServer(options);
clientTask.WaitWithoutException();
}

// smtpServer.SessionCreated += OnSmtpServerSessionCreated;
// smtpServer.SessionCompleted += OnSmtpServerSessionCompleted;
if (args[0] == "folder")
{
var clientTask = RunClientAsync(args[1], cancellationToken: cancellationTokenSource.Token);

// await smtpServer.StartAsync(cancellationToken);
Console.WriteLine("Press any key to continue");
Console.ReadKey();

// smtpServer.SessionCreated -= OnSmtpServerSessionCreated;
// smtpServer.SessionCompleted -= OnSmtpServerSessionCompleted;
//}
cancellationTokenSource.Cancel();

//static async Task RunClientAsync(
// string name,
// int limit = Int32.MaxValue,
// bool forceConnection = true,
// CancellationToken cancellationToken = default(CancellationToken))
//{
// var message = MimeKit.MimeMessage.Load(ParserOptions.Default, @"C:\Dev\Enron Corpus\maildir\allen-p\inbox\31_");

// var stopwatch = new Stopwatch();
// stopwatch.Start();

// using (var smtpClient = new SmtpClient())
// {
// var counter = 1;
// while (limit-- > 0 && cancellationToken.IsCancellationRequested == false)
// {
// try
// {
// if (smtpClient.IsConnected == false)
// {
// await smtpClient.ConnectAsync("localhost", 9025, false, cancellationToken);

// if (smtpClient.Capabilities.HasFlag(SmtpCapabilities.Authentication))
// {
// await smtpClient.AuthenticateAsync("user", "password", cancellationToken);
// }
// }

// //await SendMessageAsync(smtpClient, name, counter, cancellationToken);
// await smtpClient.SendAsync(message, cancellationToken).ConfigureAwait(false);
// }
// catch (Exception exception)
// {
// Console.WriteLine(exception);
// }
clientTask.WaitWithoutException();
}
}

// if (forceConnection)
// {
// await smtpClient.DisconnectAsync(true, cancellationToken);
// }
static async Task RunServerAsync(CancellationToken cancellationToken)
{
var options = new SmtpServerOptionsBuilder().Port(9025).Build();

// counter++;
// }
// }
var smtpServer = new SmtpServer.SmtpServer(options);

// stopwatch.Stop();
await smtpServer.StartAsync(cancellationToken);
}

// Console.WriteLine("Finished. Time Taken {0}ms", stopwatch.ElapsedMilliseconds);
//}
static async Task RunClientAsync(
string name,
int limit = Int32.MaxValue,
bool forceConnection = true,
CancellationToken cancellationToken = default(CancellationToken))
{
//var message = MimeKit.MimeMessage.Load(ParserOptions.Default, @"C:\Dev\Enron Corpus\maildir\allen-p\inbox\31_");

var message = new MimeMessage();

message.From.Add(new MailboxAddress("from@sample.com"));
message.To.Add(new MailboxAddress("to@sample.com"));
message.Subject = "Hello";
message.Body = new TextPart("plain")
{
Text = "Hello World"
};

var stopwatch = new Stopwatch();
stopwatch.Start();

var counter = 1;
using (var smtpClient = new SmtpClient())
{
while (limit-- > 0 && cancellationToken.IsCancellationRequested == false)
{
//Console.WriteLine("Name={0} Count={1}", name, counter);

try
{
if (smtpClient.IsConnected == false)
{
await smtpClient.ConnectAsync("localhost", 9025, false, cancellationToken);

if (smtpClient.Capabilities.HasFlag(SmtpCapabilities.Authentication))
{
await smtpClient.AuthenticateAsync("user", "password", cancellationToken);
}
}

await smtpClient.SendAsync(message, cancellationToken).ConfigureAwait(false);
}
catch (Exception exception)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
}

if (forceConnection)
{
await smtpClient.DisconnectAsync(true, cancellationToken);
}

counter++;
}
}

stopwatch.Stop();

Console.WriteLine();
Console.WriteLine("{0} Finished.", name);
Console.WriteLine(" {0} Messages Sent.", counter);
Console.WriteLine(" {0} Time Taken (ms).", stopwatch.ElapsedMilliseconds);
Console.WriteLine(" {0} Throughput (mps).", counter / (stopwatch.ElapsedMilliseconds / 1000.0));
}

//static async Task SendMessageAsync(SmtpClient smtpClient, string name, int counter, CancellationToken cancellationToken = default(CancellationToken))
//{
Expand Down
3 changes: 3 additions & 0 deletions Src/SmtpServer.Tests/SmtpServer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
<Name>SmtpServer</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
23 changes: 0 additions & 23 deletions Src/SmtpServer/Extensions/TaskExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,5 @@ public static async Task<T> WithCancellation<T>(this Task<T> task, CancellationT

return await task.ConfigureAwait(false);
}

/// <summary>
/// Configures the task to stop waiting when the cancellation has been requested.
/// </summary>
/// <typeparam name="T">The return type of the task.</typeparam>
/// <param name="task">The task to wait for.</param>
/// <param name="timeout">The timeout to apply to the task.</param>
/// <param name="cancellationToken">The cancellation token to watch.</param>
/// <returns>The original task.</returns>
public static async Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout, CancellationToken cancellationToken)
{
if (task != await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)))
{
if (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException(cancellationToken);
}

throw new TimeoutException();
}

return await task.ConfigureAwait(false);
}
}
}
17 changes: 0 additions & 17 deletions Src/SmtpServer/IO/INetworkClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,6 @@ public static async Task<IReadOnlyList<ArraySegment<byte>>> ReadUntilAsync(this
return Trim(await client.ReadUntilAsync(new byte[] { 13, 10 }, cancellationToken).ReturnOnAnyThread(), new byte[] { 13, 10 });
}

/// <summary>
/// Read a line from the byte stream.
/// </summary>
/// <param name="client">The stream to read a line from.</param>
/// <param name="timeout">The timeout to use whilst waiting for a line to be read.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The string that was read from the stream.</returns>
public static Task<IReadOnlyList<ArraySegment<byte>>> ReadLineAsync(this INetworkClient client, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
if (client == null)
{
throw new ArgumentNullException(nameof(client));
}

return ReadLineAsync(client, cancellationToken).WithTimeout(timeout, cancellationToken);
}

/// <summary>
/// Read a line from the byte stream.
/// </summary>
Expand Down
Loading

0 comments on commit 89edf00

Please sign in to comment.