Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

99 рядки
3.2 KiB

  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using MQTTnet.Diagnostics;
  6. using MQTTnet.Packets;
  7. namespace MQTTnet.Server
  8. {
  9. public sealed class MqttClientKeepAliveMonitor
  10. {
  11. private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch();
  12. private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch();
  13. private readonly string _clientId;
  14. private readonly Func<Task> _timeoutCallback;
  15. private readonly IMqttNetLogger _logger;
  16. private Task _workerTask;
  17. public MqttClientKeepAliveMonitor(string clientId, Func<Task> timeoutCallback, IMqttNetLogger logger)
  18. {
  19. _clientId = clientId;
  20. _timeoutCallback = timeoutCallback;
  21. _logger = logger;
  22. }
  23. public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed;
  24. public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed;
  25. public void Start(int keepAlivePeriod, CancellationToken cancellationToken)
  26. {
  27. if (keepAlivePeriod == 0)
  28. {
  29. return;
  30. }
  31. _workerTask = Task.Run(() => RunAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false), cancellationToken);
  32. }
  33. public void WaitForCompletion()
  34. {
  35. if (_workerTask != null)
  36. {
  37. Task.WaitAll(_workerTask);
  38. }
  39. }
  40. private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken)
  41. {
  42. try
  43. {
  44. _lastPacketReceivedTracker.Restart();
  45. _lastNonKeepAlivePacketReceivedTracker.Restart();
  46. while (!cancellationToken.IsCancellationRequested)
  47. {
  48. // Values described here: [MQTT-3.1.2-24].
  49. if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
  50. {
  51. _logger.Warning<MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", _clientId);
  52. if (_timeoutCallback != null)
  53. {
  54. await _timeoutCallback().ConfigureAwait(false);
  55. }
  56. return;
  57. }
  58. await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false);
  59. }
  60. }
  61. catch (OperationCanceledException)
  62. {
  63. }
  64. catch (Exception exception)
  65. {
  66. _logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
  67. }
  68. finally
  69. {
  70. _logger.Verbose<MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", _clientId);
  71. }
  72. }
  73. public void PacketReceived(MqttBasePacket packet)
  74. {
  75. _lastPacketReceivedTracker.Restart();
  76. if (!(packet is MqttPingReqPacket))
  77. {
  78. _lastNonKeepAlivePacketReceivedTracker.Restart();
  79. }
  80. }
  81. }
  82. }