You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

218 lines
7.4 KiB

  1. using MQTTnet.Core;
  2. using MQTTnet.Core.Client;
  3. using MQTTnet.Core.Packets;
  4. using MQTTnet.Core.Protocol;
  5. using MQTTnet.Core.Server;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. namespace MQTTnet.TestApp.NetCore
  14. {
  15. public static class PerformanceTest
  16. {
  17. public static async Task RunAsync()
  18. {
  19. var server = Task.Factory.StartNew(RunServerAsync, TaskCreationOptions.LongRunning);
  20. var client = Task.Factory.StartNew(() => RunClientAsync(2000, TimeSpan.FromMilliseconds(10)), TaskCreationOptions.LongRunning);
  21. await Task.WhenAll(server, client).ConfigureAwait(false);
  22. }
  23. private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval)
  24. {
  25. return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval))));
  26. }
  27. private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval)
  28. {
  29. try
  30. {
  31. var options = new MqttClientTcpOptions
  32. {
  33. Server = "localhost",
  34. ClientId = "XYZ",
  35. CleanSession = true,
  36. DefaultCommunicationTimeout = TimeSpan.FromMinutes(10)
  37. };
  38. var client = new MqttClientFactory().CreateMqttClient();
  39. client.ApplicationMessageReceived += (s, e) =>
  40. {
  41. };
  42. client.Connected += async (s, e) =>
  43. {
  44. Console.WriteLine("### CONNECTED WITH SERVER ###");
  45. await client.SubscribeAsync(new List<TopicFilter>
  46. {
  47. new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)
  48. });
  49. Console.WriteLine("### SUBSCRIBED ###");
  50. };
  51. client.Disconnected += async (s, e) =>
  52. {
  53. Console.WriteLine("### DISCONNECTED FROM SERVER ###");
  54. await Task.Delay(TimeSpan.FromSeconds(5));
  55. try
  56. {
  57. await client.ConnectAsync(options);
  58. }
  59. catch
  60. {
  61. Console.WriteLine("### RECONNECTING FAILED ###");
  62. }
  63. };
  64. try
  65. {
  66. await client.ConnectAsync(options);
  67. }
  68. catch (Exception exception)
  69. {
  70. Console.WriteLine("### CONNECTING FAILED ###" + Environment.NewLine + exception);
  71. }
  72. Console.WriteLine("### WAITING FOR APPLICATION MESSAGES ###");
  73. var testMessageCount = 10000;
  74. var message = CreateMessage();
  75. var stopwatch = Stopwatch.StartNew();
  76. for (var i = 0; i < testMessageCount; i++)
  77. {
  78. await client.PublishAsync(message);
  79. }
  80. stopwatch.Stop();
  81. Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message).");
  82. stopwatch.Restart();
  83. var sentMessagesCount = 0;
  84. while (stopwatch.ElapsedMilliseconds < 1000)
  85. {
  86. await client.PublishAsync(message);
  87. sentMessagesCount++;
  88. }
  89. Console.WriteLine($"Sending {sentMessagesCount} messages per second.");
  90. var last = DateTime.Now;
  91. var msgCount = 0;
  92. while (true)
  93. {
  94. var msgs = Enumerable.Range(0, msgChunkSize)
  95. .Select(i => CreateMessage())
  96. .ToList();
  97. Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch.");
  98. if (Console.ReadKey().KeyChar == 'c')
  99. {
  100. //send concurrent (test for raceconditions)
  101. var sendTasks = msgs
  102. .Select(msg => PublishSingleMessage(client, msg, ref msgCount))
  103. .ToList();
  104. await Task.WhenAll(sendTasks);
  105. }
  106. else
  107. {
  108. await client.PublishAsync(msgs);
  109. msgCount += msgs.Count;
  110. //send multiple
  111. }
  112. var now = DateTime.Now;
  113. if (last < now - TimeSpan.FromSeconds(1))
  114. {
  115. Console.WriteLine($"sending {msgCount} intended {msgChunkSize / interval.TotalSeconds}");
  116. msgCount = 0;
  117. last = now;
  118. }
  119. await Task.Delay(interval).ConfigureAwait(false);
  120. }
  121. }
  122. catch (Exception exception)
  123. {
  124. Console.WriteLine(exception);
  125. }
  126. }
  127. private static MqttApplicationMessage CreateMessage()
  128. {
  129. return new MqttApplicationMessage
  130. {
  131. Topic = "A/B/C",
  132. Payload = Encoding.UTF8.GetBytes("Hello World"),
  133. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce
  134. };
  135. }
  136. private static Task PublishSingleMessage(IMqttClient client, MqttApplicationMessage applicationMessage, ref int count)
  137. {
  138. Interlocked.Increment(ref count);
  139. return Task.Run(() => client.PublishAsync(applicationMessage));
  140. }
  141. private static async Task RunServerAsync()
  142. {
  143. try
  144. {
  145. var options = new MqttServerOptions
  146. {
  147. ConnectionValidator = p =>
  148. {
  149. if (p.ClientId == "SpecialClient")
  150. {
  151. if (p.Username != "USER" || p.Password != "PASS")
  152. {
  153. return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
  154. }
  155. }
  156. return MqttConnectReturnCode.ConnectionAccepted;
  157. },
  158. DefaultCommunicationTimeout = TimeSpan.FromMinutes(10)
  159. };
  160. var mqttServer = new MqttServerFactory().CreateMqttServer(options);
  161. var msgs = 0;
  162. var stopwatch = Stopwatch.StartNew();
  163. mqttServer.ApplicationMessageReceived += (sender, args) =>
  164. {
  165. msgs++;
  166. if (stopwatch.ElapsedMilliseconds > 1000)
  167. {
  168. Console.WriteLine($"received {msgs}");
  169. msgs = 0;
  170. stopwatch.Restart();
  171. }
  172. };
  173. await mqttServer.StartAsync();
  174. Console.WriteLine("Press any key to exit.");
  175. Console.ReadLine();
  176. await mqttServer.StopAsync();
  177. }
  178. catch (Exception e)
  179. {
  180. Console.WriteLine(e);
  181. }
  182. Console.ReadLine();
  183. }
  184. }
  185. }