This commit is contained in:
Christian
2022-02-20 21:10:46 +01:00
committed by GitHub
parent 47e674e4d3
commit 2ce9b94ec9
608 changed files with 22364 additions and 19420 deletions
+55
View File
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Diagnostics;
namespace MQTTnet.TestApp
{
public static class ClientFlowTest
{
public static async Task RunAsync()
{
try
{
var logger = new MqttNetEventLogger();
MqttNetConsoleLogger.ForwardToConsole(logger);
var factory = new MqttFactory(logger);
var client = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer("localhost")
.Build();
Console.WriteLine("BEFORE CONNECT");
await client.ConnectAsync(options);
Console.WriteLine("AFTER CONNECT");
Console.WriteLine("BEFORE SUBSCRIBE");
await client.SubscribeAsync("test/topic");
Console.WriteLine("AFTER SUBSCRIBE");
Console.WriteLine("BEFORE PUBLISH");
await client.PublishStringAsync("test/topic", "payload");
Console.WriteLine("AFTER PUBLISH");
await Task.Delay(1000);
Console.WriteLine("BEFORE DISCONNECT");
await client.DisconnectAsync();
Console.WriteLine("AFTER DISCONNECT");
Console.WriteLine("FINISHED");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
+102
View File
@@ -0,0 +1,102 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using MQTTnet.Client;
using System;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Diagnostics;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
namespace MQTTnet.TestApp
{
public static class ClientTest
{
public static async Task RunAsync()
{
try
{
var logger = new MqttNetEventLogger();
MqttNetConsoleLogger.ForwardToConsole(logger);
var factory = new MqttFactory(logger);
var client = factory.CreateMqttClient();
var clientOptions = new MqttClientOptions
{
ChannelOptions = new MqttClientTcpOptions
{
Server = "127.0.0.1"
}
};
client.ApplicationMessageReceivedAsync += e =>
{
Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###");
Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}");
Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}");
Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}");
Console.WriteLine();
return PlatformAbstractionLayer.CompletedTask;
};
client.ConnectedAsync += async e =>
{
Console.WriteLine("### CONNECTED WITH SERVER ###");
await client.SubscribeAsync("#");
Console.WriteLine("### SUBSCRIBED ###");
};
client.DisconnectedAsync += async e =>
{
Console.WriteLine("### DISCONNECTED FROM SERVER ###");
await Task.Delay(TimeSpan.FromSeconds(5));
try
{
await client.ConnectAsync(clientOptions);
}
catch
{
Console.WriteLine("### RECONNECTING FAILED ###");
}
};
try
{
await client.ConnectAsync(clientOptions);
}
catch (Exception exception)
{
Console.WriteLine("### CONNECTING FAILED ###" + Environment.NewLine + exception);
}
Console.WriteLine("### WAITING FOR APPLICATION MESSAGES ###");
while (true)
{
Console.ReadLine();
await client.SubscribeAsync("test");
var applicationMessage = new MqttApplicationMessageBuilder()
.WithTopic("A/B/C")
.WithPayload("Hello World")
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.Build();
await client.PublishAsync(applicationMessage);
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
}
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<DebugType>Full</DebugType>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<IsPackable>false</IsPackable>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
<DisableImplicitAspNetCoreAnalyzers>true</DisableImplicitAspNetCoreAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Microsoft.CodeAnalysis.Compilers" Version="4.0.1" />
<PackageReference Include="Microsoft.Net.Compilers" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj" />
<ProjectReference Include="..\..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj" />
<ProjectReference Include="..\..\Source\MQTTnet\MQTTnet.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Start.bat">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+108
View File
@@ -0,0 +1,108 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using System.Collections.Generic;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
namespace MQTTnet.TestApp
{
public static class ManagedClientTest
{
public static async Task RunAsync()
{
var ms = new ClientRetainedMessageHandler();
var options = new ManagedMqttClientOptions
{
ClientOptions = new MqttClientOptions
{
ClientId = "MQTTnetManagedClientTest",
Credentials = new RandomPassword(),
ChannelOptions = new MqttClientTcpOptions
{
Server = "broker.hivemq.com"
}
},
AutoReconnectDelay = TimeSpan.FromSeconds(1),
Storage = ms
};
try
{
var managedClient = new MqttFactory().CreateManagedMqttClient();
managedClient.ApplicationMessageReceivedAsync += e =>
{
Console.WriteLine(">> RECEIVED: " + e.ApplicationMessage.Topic);
return PlatformAbstractionLayer.CompletedTask;
};
await managedClient.StartAsync(options);
await managedClient.EnqueueAsync(topic: "Step", payload: "1");
await managedClient.EnqueueAsync(topic: "Step", payload: "2", MqttQualityOfServiceLevel.AtLeastOnce);
await managedClient.SubscribeAsync(topic: "xyz", qualityOfServiceLevel: MqttQualityOfServiceLevel.AtMostOnce);
await managedClient.SubscribeAsync(topic: "abc", qualityOfServiceLevel: MqttQualityOfServiceLevel.AtMostOnce);
await managedClient.EnqueueAsync(topic: "Step", payload: "3");
Console.WriteLine("Managed client started.");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public sealed class RandomPassword : IMqttClientCredentialsProvider
{
public string GetUserName(MqttClientOptions clientOptions)
{
return "the_static_user";
}
public byte[] GetPassword(MqttClientOptions clientOptions)
{
return Guid.NewGuid().ToByteArray();
}
}
public class ClientRetainedMessageHandler : IManagedMqttClientStorage
{
const string Filename = @"RetainedMessages.json";
public Task SaveQueuedMessagesAsync(IList<ManagedMqttApplicationMessage> messages)
{
File.WriteAllText(Filename, JsonConvert.SerializeObject(messages));
return Task.FromResult(0);
}
public Task<IList<ManagedMqttApplicationMessage>> LoadQueuedMessagesAsync()
{
IList<ManagedMqttApplicationMessage> retainedMessages;
if (File.Exists(Filename))
{
var json = File.ReadAllText(Filename);
retainedMessages = JsonConvert.DeserializeObject<List<ManagedMqttApplicationMessage>>(json);
}
else
{
retainedMessages = new List<ManagedMqttApplicationMessage>();
}
return Task.FromResult(retainedMessages);
}
}
}
}
@@ -0,0 +1,344 @@
using MQTTnet.Client;
using MQTTnet.Server;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
namespace MQTTnet.TestApp
{
/// <summary>
/// Connect a number of publisher clients and one subscriber client, then publish messages and measure
/// the number of messages per second that can be exchanged between publishers and subscriber.
/// Measurements are performed for subscriptions containing no wildcard, a single wildcard or multiple wildcards.
/// </summary>
public class MessageThroughputTest
{
// Change these constants to suit
const int NumPublishers = 5000;
const int NumTopicsPerPublisher = 10;
// Note: Other code changes may be required when changing this constant:
const int NumSubscribers = 1; // Fixed
// Number of publish calls before a response for all published messages is awaited.
// This must be limited to a reasonable value that the server or TCP pipeline can handle.
const int NumPublishCallsPerBatch = 250;
// Message counters are set/reset in the PublishAllAsync loop
int _messagesReceivedCount;
int _messagesExpectedCount;
CancellationTokenSource _cancellationTokenSource;
MqttServer _mqttServer;
Dictionary<string, Client.MqttClient> _mqttPublisherClientsByPublisherName;
List<Client.MqttClient> _mqttSubscriberClients;
Dictionary<string, List<string>> _topicsByPublisher;
Dictionary<string, List<string>> _singleWildcardTopicsByPublisher;
Dictionary<string, List<string>> _multiWildcardTopicsByPublisher;
public async Task Run()
{
try
{
Console.WriteLine();
Console.WriteLine("Begin message throughput test");
Console.WriteLine();
Console.WriteLine("Number of publishers: " + NumPublishers);
Console.WriteLine("Number of published topics (total): " + NumPublishers * NumTopicsPerPublisher);
Console.WriteLine("Number of subscribers: " + NumSubscribers);
await Setup();
await Subscribe_to_No_Wildcard_Topics();
await Subscribe_to_Single_Wildcard_Topics();
await Subscribe_to_Multi_Wildcard_Topics();
Console.WriteLine();
Console.WriteLine("End message throughput test");
}
catch (Exception ex)
{
ConsoleWriteLineError(ex.Message);
}
finally
{
await Cleanup();
}
}
public async Task Setup()
{
new TopicGenerator().Generate(NumPublishers, NumTopicsPerPublisher, out _topicsByPublisher, out _singleWildcardTopicsByPublisher, out _multiWildcardTopicsByPublisher);
var serverOptions = new MqttServerOptionsBuilder().WithDefaultEndpoint().Build();
var factory = new MqttFactory();
_mqttServer = factory.CreateMqttServer(serverOptions);
await _mqttServer.StartAsync();
Console.WriteLine();
Console.WriteLine("Begin connect " + NumPublishers + " publisher(s)...");
var stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
_mqttPublisherClientsByPublisherName = new Dictionary<string, Client.MqttClient>();
foreach (var pt in _topicsByPublisher)
{
var publisherName = pt.Key;
var mqttClient = factory.CreateMqttClient();
var publisherOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost")
.WithClientId(publisherName)
.Build();
await mqttClient.ConnectAsync(publisherOptions);
_mqttPublisherClientsByPublisherName.Add(publisherName, mqttClient);
}
stopWatch.Stop();
Console.Write(string.Format("{0} publisher(s) connected in {1:0.000} seconds, ", NumPublishers, stopWatch.ElapsedMilliseconds / 1000.0));
Console.WriteLine(string.Format("connections per second: {0:0.000}", NumPublishers / (stopWatch.ElapsedMilliseconds / 1000.0)));
_mqttSubscriberClients = new List<Client.MqttClient>();
for (var i = 0; i < NumSubscribers; ++i)
{
var mqttClient = factory.CreateMqttClient();
var subsriberOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost")
.WithClientId("sub" + i)
.Build();
await mqttClient.ConnectAsync(subsriberOptions);
mqttClient.ApplicationMessageReceivedAsync += HandleApplicationMessageReceivedAsync;
_mqttSubscriberClients.Add(mqttClient);
}
}
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
{
// count messages and signal cancellation when expected message count is reached
++_messagesReceivedCount;
if (_messagesReceivedCount == _messagesExpectedCount)
{
_cancellationTokenSource.Cancel();
}
return Implementations.PlatformAbstractionLayer.CompletedTask;
}
public async Task Cleanup()
{
foreach (var mqttClient in _mqttSubscriberClients)
{
await mqttClient.DisconnectAsync();
mqttClient.ApplicationMessageReceivedAsync -= HandleApplicationMessageReceivedAsync;
mqttClient.Dispose();
}
foreach (var pub in _mqttPublisherClientsByPublisherName)
{
var mqttClient = pub.Value;
await mqttClient.DisconnectAsync();
mqttClient.Dispose();
}
await _mqttServer.StopAsync();
_mqttServer.Dispose();
}
/// <summary>
/// Measure no-wildcard topic subscription message exchange performance
/// </summary>
public Task Subscribe_to_No_Wildcard_Topics()
{
return ProcessMessages(_topicsByPublisher, "no wildcards");
}
/// <summary>
/// Measure single-wildcard topic subscription message exchange performance
/// </summary>
public Task Subscribe_to_Single_Wildcard_Topics()
{
return ProcessMessages(_singleWildcardTopicsByPublisher, "single wildcard");
}
/// <summary>
/// Measure multi-wildcard topic subscription message exchange performance
/// </summary>
public Task Subscribe_to_Multi_Wildcard_Topics()
{
return ProcessMessages(_multiWildcardTopicsByPublisher, "multi wildcard");
}
/// <summary>
/// Subcribe to all topics, then run message exchange
/// </summary>
public async Task ProcessMessages(Dictionary<string, List<string>> topicsByPublisher, string topicTypeDescription)
{
var numTopics = CountTopics(topicsByPublisher);
Console.WriteLine();
Console.Write(string.Format("Subscribing to {0} topics ", numTopics));
ConsoleWriteInfo(string.Format("({0})", topicTypeDescription));
Console.WriteLine(string.Format(" for {0} subscriber(s)...", NumSubscribers));
var stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
// each subscriber subscribes to all topics, one call per topic
foreach (var subscriber in _mqttSubscriberClients)
{
foreach (var tp in topicsByPublisher)
{
var topics = tp.Value;
foreach (var topic in topics)
{
var topicFilter = new Packets.MqttTopicFilter() { Topic = topic };
await subscriber.SubscribeAsync(topicFilter).ConfigureAwait(false);
}
}
}
stopWatch.Stop();
Console.Write(string.Format("{0} subscriber(s) subscribed in {1:0.000} seconds, ", NumSubscribers, stopWatch.ElapsedMilliseconds / 1000.0));
Console.WriteLine(string.Format("subscribe calls per second: {0:0.000}", numTopics / (stopWatch.ElapsedMilliseconds / 1000.0)));
await PublishAllAsync();
Console.WriteLine(string.Format("Unsubscribing {0} topics ({1}) for {2} subscriber(s)...", numTopics, topicTypeDescription, NumSubscribers));
stopWatch.Restart();
// unsubscribe to all topics, one call per topic
foreach (var subscriber in _mqttSubscriberClients)
{
foreach (var tp in topicsByPublisher)
{
var topics = tp.Value;
foreach (var topic in topics)
{
var topicFilter = new Packets.MqttTopicFilter() { Topic = topic };
MqttClientUnsubscribeOptions options =
new MqttClientUnsubscribeOptionsBuilder()
.WithTopicFilter(topicFilter)
.Build();
await subscriber.UnsubscribeAsync(options).ConfigureAwait(false);
}
}
}
stopWatch.Stop();
Console.Write(string.Format("{0} subscriber(s) unsubscribed in {1:0.000} seconds, ", NumSubscribers, stopWatch.ElapsedMilliseconds / 1000.0));
Console.WriteLine(string.Format("unsubscribe calls per second: {0:0.000}", numTopics / (stopWatch.ElapsedMilliseconds / 1000.0)));
}
/// <summary>
/// Publish messages in batches of NumPublishCallsPerBatch, wait for messages sent to subscriber
/// </summary>
async Task PublishAllAsync()
{
Console.WriteLine("Begin message exchange...");
int publisherIndexCounter = 0; // index to loop around all publishers to publish
int topicIndexCounter = 0; // index to loop around all topics to publish
int totalNumMessagesReceived = 0;
var publisherNames = _topicsByPublisher.Keys.ToList();
// There should be one message received per publish
_messagesExpectedCount = NumPublishCallsPerBatch;
var stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
// Loop for a while and exchange messages
while (stopWatch.ElapsedMilliseconds < 10000)
{
_messagesReceivedCount = 0;
_cancellationTokenSource = new CancellationTokenSource();
for (var publishCallCount = 0; publishCallCount < NumPublishCallsPerBatch; ++publishCallCount)
{
// pick a publisher
var publisherName = publisherNames[publisherIndexCounter % publisherNames.Count];
var publisherTopics = _topicsByPublisher[publisherName];
// pick a publisher topic
var topic = publisherTopics[topicIndexCounter % publisherTopics.Count];
var message = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.Build();
await _mqttPublisherClientsByPublisherName[publisherName].PublishAsync(message).ConfigureAwait(false);
++topicIndexCounter;
++publisherIndexCounter;
}
// Wait for at least one message per publish to be received by subscriber (in the subscriber's application message handler),
// then loop around to send another batch
try
{
await Task.Delay(30000, _cancellationTokenSource.Token).ConfigureAwait(false);
}
catch
{
}
_cancellationTokenSource.Dispose();
if (_messagesReceivedCount < _messagesExpectedCount)
{
ConsoleWriteLineError(string.Format("Messages Received Count mismatch, expected {0}, received {1}", _messagesExpectedCount, _messagesReceivedCount));
return;
}
totalNumMessagesReceived += _messagesReceivedCount;
}
stopWatch.Stop();
System.Console.Write(string.Format("{0} messages published and received in {1:0.000} seconds, ", totalNumMessagesReceived, stopWatch.ElapsedMilliseconds / 1000.0));
ConsoleWriteLineSuccess(string.Format("messages per second: {0}", (int)(totalNumMessagesReceived / (stopWatch.ElapsedMilliseconds / 1000.0))));
}
int CountTopics(Dictionary<string, List<string>> topicsByPublisher)
{
var count = 0;
foreach (var tp in topicsByPublisher)
{
count += tp.Value.Count;
}
return count;
}
void ConsoleWriteLineError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ResetColor();
}
void ConsoleWriteLineSuccess(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(message);
Console.ResetColor();
}
void ConsoleWriteInfo(string message)
{
Console.ForegroundColor = ConsoleColor.White;
Console.Write(message);
Console.ResetColor();
}
}
}
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text;
using MQTTnet.Diagnostics;
namespace MQTTnet.TestApp
{
public static class MqttNetConsoleLogger
{
static readonly object _lock = new object();
public static void ForwardToConsole(MqttNetEventLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
logger.LogMessagePublished -= PrintToConsole;
logger.LogMessagePublished += PrintToConsole;
}
public static void PrintToConsole(string message, ConsoleColor color)
{
lock (_lock)
{
var backupColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.Write(message);
Console.ForegroundColor = backupColor;
}
}
static void PrintToConsole(object sender, MqttNetLogMessagePublishedEventArgs e)
{
var output = new StringBuilder();
output.AppendLine($">> [{e.LogMessage.Timestamp:O}] [{e.LogMessage.ThreadId}] [{e.LogMessage.Source}] [{e.LogMessage.Level}]: {e.LogMessage.Message}");
if (e.LogMessage.Exception != null)
{
output.AppendLine(e.LogMessage.Exception.ToString());
}
var color = ConsoleColor.Red;
switch (e.LogMessage.Level)
{
case MqttNetLogLevel.Error:
color = ConsoleColor.Red;
break;
case MqttNetLogLevel.Warning:
color = ConsoleColor.Yellow;
break;
case MqttNetLogLevel.Info:
color = ConsoleColor.Green;
break;
case MqttNetLogLevel.Verbose:
color = ConsoleColor.Gray;
break;
}
PrintToConsole(output.ToString(), color);
}
}
}
File diff suppressed because one or more lines are too long
+95
View File
@@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using MQTTnet.Diagnostics;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.TestApp
{
public static class Program
{
public static void Main()
{
Console.WriteLine($"MQTTnet - TestApp.{TargetFrameworkProvider.TargetFramework}");
Console.WriteLine("1 = Start client");
Console.WriteLine("2 = Start server");
Console.WriteLine("3 = Start performance test");
Console.WriteLine("4 = Start managed client");
Console.WriteLine("5 = Start public broker test");
Console.WriteLine("6 = Start server & client");
Console.WriteLine("7 = Client flow test");
Console.WriteLine("8 = Start performance test (client only)");
Console.WriteLine("9 = Start server (no trace)");
Console.WriteLine("a = Start QoS 2 benchmark");
Console.WriteLine("b = Start QoS 1 benchmark");
Console.WriteLine("c = Start QoS 0 benchmark");
Console.WriteLine("d = Start server with logging");
Console.WriteLine("e = Start Message Throughput Test");
var pressedKey = Console.ReadKey(true);
if (pressedKey.KeyChar == '1')
{
Task.Run(ClientTest.RunAsync);
}
else if (pressedKey.KeyChar == '2')
{
Task.Run(ServerTest.RunAsync);
}
else if (pressedKey.KeyChar == '3')
{
Task.Run(PerformanceTest.RunClientAndServer);
}
else if (pressedKey.KeyChar == '4')
{
Task.Run(ManagedClientTest.RunAsync);
}
else if (pressedKey.KeyChar == '5')
{
Task.Run(PublicBrokerTest.RunAsync);
}
else if (pressedKey.KeyChar == '6')
{
Task.Run(ServerAndClientTest.RunAsync);
}
else if (pressedKey.KeyChar == '7')
{
Task.Run(ClientFlowTest.RunAsync);
}
else if (pressedKey.KeyChar == '8')
{
PerformanceTest.RunClientOnly();
return;
}
else if (pressedKey.KeyChar == '9')
{
ServerTest.RunEmptyServer();
return;
}
else if (pressedKey.KeyChar == 'a')
{
Task.Run(PerformanceTest.RunQoS2Test);
}
else if (pressedKey.KeyChar == 'b')
{
Task.Run(PerformanceTest.RunQoS1Test);
}
else if (pressedKey.KeyChar == 'c')
{
Task.Run(PerformanceTest.RunQoS0Test);
}
else if (pressedKey.KeyChar == 'd')
{
Task.Run(ServerTest.RunEmptyServerWithLogging);
}
else if (pressedKey.KeyChar == 'e')
{
Task.Run(new MessageThroughputTest().Run);
}
Thread.Sleep(Timeout.Infinite);
}
}
}
+179
View File
@@ -0,0 +1,179 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using MQTTnet.Client;
using System;
using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Formatter;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
namespace MQTTnet.TestApp
{
public static class PublicBrokerTest
{
public static async Task RunAsync()
{
// MqttNetConsoleLogger.ForwardToConsole();
// For most of these connections to work, set output target to Net5.0.
#if NET5_0_OR_GREATER
// TLS13 is only available in Net5.0
var unsafeTls13 = new MqttClientOptionsBuilderTlsParameters
{
UseTls = true,
SslProtocol = SslProtocols.Tls13,
// Don't use this in production code. This handler simply allows any invalid certificate to work.
CertificateValidationHandler = w => true
};
#endif
// Also defining TLS12 for servers that don't seem no to support TLS13.
var unsafeTls12 = new MqttClientOptionsBuilderTlsParameters
{
UseTls = true,
SslProtocol = SslProtocols.Tls12,
// Don't use this in production code. This handler simply allows any invalid certificate to work.
CertificateValidationHandler = w => true
};
// mqtt.eclipseprojects.io
await ExecuteTestAsync("mqtt.eclipseprojects.io TCP",
new MqttClientOptionsBuilder().WithTcpServer("mqtt.eclipseprojects.io", 1883)
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("mqtt.eclipseprojects.io WS",
new MqttClientOptionsBuilder().WithWebSocketServer("mqtt.eclipseprojects.io:80/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
#if NET5_0_OR_GREATER
await ExecuteTestAsync("mqtt.eclipseprojects.io WS TLS13",
new MqttClientOptionsBuilder().WithWebSocketServer("mqtt.eclipseprojects.io:443/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls13).Build());
#endif
// test.mosquitto.org
await ExecuteTestAsync("test.mosquitto.org TCP",
new MqttClientOptionsBuilder().WithTcpServer("test.mosquitto.org", 1883)
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("test.mosquitto.org TCP - Authenticated",
new MqttClientOptionsBuilder().WithTcpServer("test.mosquitto.org", 1884)
.WithCredentials("rw", "readwrite")
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("test.mosquitto.org TCP TLS12",
new MqttClientOptionsBuilder().WithTcpServer("test.mosquitto.org", 8883)
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls12).Build());
#if NET5_0_OR_GREATER
await ExecuteTestAsync("test.mosquitto.org TCP TLS13",
new MqttClientOptionsBuilder().WithTcpServer("test.mosquitto.org", 8883)
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls13).Build());
#endif
await ExecuteTestAsync("test.mosquitto.org TCP TLS12 - Authenticated",
new MqttClientOptionsBuilder().WithTcpServer("test.mosquitto.org", 8885)
.WithCredentials("rw", "readwrite")
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls12).Build());
await ExecuteTestAsync("test.mosquitto.org WS",
new MqttClientOptionsBuilder().WithWebSocketServer("test.mosquitto.org:8080/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("test.mosquitto.org WS TLS12",
new MqttClientOptionsBuilder().WithWebSocketServer("test.mosquitto.org:8081/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls12).Build());
// broker.emqx.io
await ExecuteTestAsync("broker.emqx.io TCP",
new MqttClientOptionsBuilder().WithTcpServer("broker.emqx.io", 1883)
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("broker.emqx.io TCP TLS12",
new MqttClientOptionsBuilder().WithTcpServer("broker.emqx.io", 8883)
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls12).Build());
#if NET5_0_OR_GREATER
await ExecuteTestAsync("broker.emqx.io TCP TLS13",
new MqttClientOptionsBuilder().WithTcpServer("broker.emqx.io", 8883)
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls13).Build());
#endif
await ExecuteTestAsync("broker.emqx.io WS",
new MqttClientOptionsBuilder().WithWebSocketServer("broker.emqx.io:8083/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("broker.emqx.io WS TLS12",
new MqttClientOptionsBuilder().WithWebSocketServer("broker.emqx.io:8084/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).WithTls(unsafeTls12).Build());
// broker.hivemq.com
await ExecuteTestAsync("broker.hivemq.com TCP",
new MqttClientOptionsBuilder().WithTcpServer("broker.hivemq.com", 1883)
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
await ExecuteTestAsync("broker.hivemq.com WS",
new MqttClientOptionsBuilder().WithWebSocketServer("broker.hivemq.com:8000/mqtt")
.WithProtocolVersion(MqttProtocolVersion.V311).Build());
// mqtt.swifitch.cz: Does not seem to operate any more
// cloudmqtt.com: Cannot test because it does not offer a free plan any more.
Write("Finished.", ConsoleColor.White);
Console.ReadLine();
}
static async Task ExecuteTestAsync(string name, MqttClientOptions options)
{
try
{
Write("Testing '" + name + "'... ", ConsoleColor.Gray);
var factory = new MqttFactory();
//factory.UseWebSocket4Net();
var client = factory.CreateMqttClient();
var topic = Guid.NewGuid().ToString();
MqttApplicationMessage receivedMessage = null;
client.ApplicationMessageReceivedAsync += e =>
{
receivedMessage = e.ApplicationMessage;
return PlatformAbstractionLayer.CompletedTask;
};
await client.ConnectAsync(options);
await client.SubscribeAsync(topic, MqttQualityOfServiceLevel.AtLeastOnce);
await client.PublishStringAsync(topic, "Hello_World", MqttQualityOfServiceLevel.AtLeastOnce);
SpinWait.SpinUntil(() => receivedMessage != null, 5000);
if (receivedMessage?.Topic != topic || receivedMessage?.ConvertPayloadToString() != "Hello_World")
{
throw new Exception("Message invalid.");
}
await client.UnsubscribeAsync(topic);
await client.DisconnectAsync();
Write("[OK]\n", ConsoleColor.Green);
}
catch (Exception e)
{
Write("[FAILED] " + e.Message + "\n", ConsoleColor.Red);
}
}
static void Write(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.Write(message);
}
}
}
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Diagnostics;
using MQTTnet.Server;
namespace MQTTnet.TestApp
{
public static class ServerAndClientTest
{
public static async Task RunAsync()
{
var logger = new MqttNetEventLogger();
MqttNetConsoleLogger.ForwardToConsole(logger);
var factory = new MqttFactory(logger);
var server = factory.CreateMqttServer( new MqttServerOptionsBuilder().Build());
var client = factory.CreateMqttClient();
await server.StartAsync();
var clientOptions = new MqttClientOptionsBuilder().WithTcpServer("localhost").Build();
await client.ConnectAsync(clientOptions);
await Task.Delay(Timeout.Infinite);
}
}
}
+198
View File
@@ -0,0 +1,198 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Diagnostics;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Newtonsoft.Json;
namespace MQTTnet.TestApp
{
public static class ServerTest
{
public static void RunEmptyServer()
{
var mqttServer = new MqttFactory().CreateMqttServer(new MqttServerOptions());
mqttServer.StartAsync().GetAwaiter().GetResult();
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
public static void RunEmptyServerWithLogging()
{
var logger = new MqttNetEventLogger();
MqttNetConsoleLogger.ForwardToConsole(logger);
var mqttFactory = new MqttFactory(logger);
var mqttServer = mqttFactory.CreateMqttServer(new MqttServerOptions());
mqttServer.StartAsync().GetAwaiter().GetResult();
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
public static async Task RunAsync()
{
try
{
var options = new MqttServerOptions();
// Extend the timestamp for all messages from clients.
// Protect several topics from being subscribed from every client.
//var certificate = new X509Certificate(@"C:\certs\test\test.cer", "");
//options.TlsEndpointOptions.Certificate = certificate.Export(X509ContentType.Cert);
//options.ConnectionBacklog = 5;
//options.DefaultEndpointOptions.IsEnabled = true;
//options.TlsEndpointOptions.IsEnabled = false;
var mqttServer = new MqttFactory().CreateMqttServer(options);
const string Filename = "C:\\MQTT\\RetainedMessages.json";
mqttServer.RetainedMessageChangedAsync += e =>
{
var directory = Path.GetDirectoryName(Filename);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
File.WriteAllText(Filename, JsonConvert.SerializeObject(e.StoredRetainedMessages));
return Task.FromResult(0);
};
mqttServer.RetainedMessagesClearedAsync += e =>
{
File.Delete(Filename);
return Task.FromResult(0);
};
mqttServer.LoadingRetainedMessageAsync += e =>
{
List<MqttApplicationMessage> retainedMessages;
if (File.Exists(Filename))
{
var json = File.ReadAllText(Filename);
retainedMessages = JsonConvert.DeserializeObject<List<MqttApplicationMessage>>(json);
}
else
{
retainedMessages = new List<MqttApplicationMessage>();
}
e.LoadedRetainedMessages = retainedMessages;
return Task.FromResult(0);
};
mqttServer.InterceptingPublishAsync += e =>
{
if (MqttTopicFilterComparer.Compare(e.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#") == MqttTopicFilterCompareResult.IsMatch)
{
// Replace the payload with the timestamp. But also extending a JSON
// based payload with the timestamp is a suitable use case.
e.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
}
if (e.ApplicationMessage.Topic == "not_allowed_topic")
{
e.ProcessPublish = false;
e.CloseConnection = true;
}
return PlatformAbstractionLayer.CompletedTask;
};
mqttServer.ValidatingConnectionAsync += e =>
{
if (e.ClientId == "SpecialClient")
{
if (e.Username != "USER" || e.Password != "PASS")
{
e.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
}
}
return PlatformAbstractionLayer.CompletedTask;
};
mqttServer.InterceptingSubscriptionAsync += e =>
{
if (e.TopicFilter.Topic.StartsWith("admin/foo/bar") && e.ClientId != "theAdmin")
{
e.Response.ReasonCode = MqttSubscribeReasonCode.ImplementationSpecificError;
}
if (e.TopicFilter.Topic.StartsWith("the/secret/stuff") && e.ClientId != "Imperator")
{
e.Response.ReasonCode = MqttSubscribeReasonCode.ImplementationSpecificError;
e.CloseConnection = true;
}
return PlatformAbstractionLayer.CompletedTask;
};
mqttServer.InterceptingPublishAsync += e =>
{
MqttNetConsoleLogger.PrintToConsole(
$"'{e.ClientId}' reported '{e.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[0])}'",
ConsoleColor.Magenta);
return PlatformAbstractionLayer.CompletedTask;
};
//options.ApplicationMessageInterceptor = c =>
//{
// if (c.ApplicationMessage.Payload == null || c.ApplicationMessage.Payload.Length == 0)
// {
// return;
// }
// try
// {
// var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload));
// var timestampProperty = content.Property("timestamp");
// if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null)
// {
// timestampProperty.Value = DateTime.Now.ToString("O");
// c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString());
// }
// }
// catch (Exception)
// {
// }
//};
mqttServer.ClientConnectedAsync += e =>
{
Console.Write("Client disconnected event fired.");
return PlatformAbstractionLayer.CompletedTask;
};
await mqttServer.StartAsync();
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
await mqttServer.StopAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
}
}
+1
View File
@@ -0,0 +1 @@
dotnet MQTTnet.TestApp.NetCore.dll
+84
View File
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace MQTTnet.TestApp
{
public class TopicGenerator
{
public void Generate(
int numPublishers, int numTopicsPerPublisher,
out Dictionary<string, List<string>> topicsByPublisher,
out Dictionary<string, List<string>> singleWildcardTopicsByPublisher,
out Dictionary<string, List<string>> multiWildcardTopicsByPublisher
)
{
topicsByPublisher = new Dictionary<string, List<string>>();
singleWildcardTopicsByPublisher = new Dictionary<string, List<string>>();
multiWildcardTopicsByPublisher = new Dictionary<string, List<string>>();
// Find some reasonable distribution across three topic levels
var topicsPerLevel = (int)Math.Pow(numTopicsPerPublisher, (1.0 / 3.0));
int numLevel1Topics = topicsPerLevel;
if (numLevel1Topics <= 0)
{
numLevel1Topics = 1;
}
int numLevel2Topics = topicsPerLevel;
if (numLevel2Topics <= 0)
{
numLevel2Topics = 1;
}
var maxNumLevel3Topics = 1 + (int)((double)numTopicsPerPublisher / numLevel1Topics / numLevel2Topics);
if (maxNumLevel3Topics <= 0)
{
maxNumLevel3Topics = 1;
}
for (var p = 0; p < numPublishers; ++p)
{
int publisherTopicCount = 0;
var publisherName = "pub" + p;
for (var l1 = 0; l1 < numLevel1Topics; ++l1)
{
for (var l2 = 0; l2 < numLevel2Topics; ++l2)
{
for (var l3 = 0; l3 < maxNumLevel3Topics; ++l3)
{
if (publisherTopicCount >= numTopicsPerPublisher)
break;
var topic = string.Format("{0}/building{1}/level{2}/sensor{3}", publisherName, l1 + 1, l2 + 1, l3 + 1);
AddPublisherTopic(publisherName, topic, topicsByPublisher);
if (l2 == 0)
{
var singleWildcardTopic = string.Format("{0}/building{1}/+/sensor{2}", publisherName, l1 + 1, l3 + 1);
AddPublisherTopic(publisherName, singleWildcardTopic, singleWildcardTopicsByPublisher);
if (l1 == 0)
{
var multiWildcardTopic = string.Format("{0}/+/level{1}/+", publisherName, l3 + 1);
AddPublisherTopic(publisherName, multiWildcardTopic, multiWildcardTopicsByPublisher);
}
}
++publisherTopicCount;
}
}
}
}
}
void AddPublisherTopic(string publisherName, string topic, Dictionary<string, List<string>> topicsByPublisher)
{
List<string> topicList;
if (!topicsByPublisher.TryGetValue(publisherName, out topicList))
{
topicList = new List<string>();
topicsByPublisher.Add(publisherName, topicList);
}
topicList.Add(topic);
}
}
}