mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-25 07:41:32 +08:00
Improve connection disposal.
This commit is contained in:
@@ -28,7 +28,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
|
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
|
||||||
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol))
|
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await adapter.RunWebSocketConnectionAsync(webSocket, context);
|
await adapter.RunWebSocketConnectionAsync(webSocket, context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
_input = Connection.Transport.Input;
|
_input = Connection.Transport.Input;
|
||||||
_output = Connection.Transport.Output;
|
_output = Connection.Transport.Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_reader = new SpanBasedMqttPacketBodyReader();
|
_reader = new SpanBasedMqttPacketBodyReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +32,10 @@ namespace MQTTnet.AspNetCore
|
|||||||
private PipeWriter _output;
|
private PipeWriter _output;
|
||||||
private readonly SpanBasedMqttPacketBodyReader _reader;
|
private readonly SpanBasedMqttPacketBodyReader _reader;
|
||||||
|
|
||||||
public string Endpoint
|
public string Endpoint
|
||||||
{
|
{
|
||||||
get {
|
get
|
||||||
|
{
|
||||||
var connection = Http?.HttpContext?.Connection;
|
var connection = Http?.HttpContext?.Connection;
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
{
|
{
|
||||||
@@ -53,12 +53,12 @@ namespace MQTTnet.AspNetCore
|
|||||||
public ConnectionContext Connection { get; }
|
public ConnectionContext Connection { get; }
|
||||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||||
|
|
||||||
public long BytesSent { get; set; }
|
public long BytesSent { get; set; }
|
||||||
public long BytesReceived { get; set; }
|
public long BytesReceived { get; set; }
|
||||||
|
|
||||||
public Action ReadingPacketStartedCallback { get; set; }
|
public Action ReadingPacketStartedCallback { get; set; }
|
||||||
public Action ReadingPacketCompletedCallback { get; set; }
|
public Action ReadingPacketCompletedCallback { get; set; }
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||||
@@ -145,7 +145,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var formatter = PacketFormatterAdapter;
|
var formatter = PacketFormatterAdapter;
|
||||||
|
|
||||||
|
|
||||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
{
|
{
|
||||||
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
|
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
|
||||||
{
|
{
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
public override async Task OnConnectedAsync(ConnectionContext connection)
|
public override async Task OnConnectedAsync(ConnectionContext connection)
|
||||||
{
|
{
|
||||||
@@ -25,10 +25,11 @@ namespace MQTTnet.AspNetCore
|
|||||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||||
using (var adapter = new MqttConnectionContext(formatter, connection))
|
using (var adapter = new MqttConnectionContext(formatter, connection))
|
||||||
{
|
{
|
||||||
var args = new MqttServerAdapterClientAcceptedEventArgs(adapter);
|
var clientHandler = ClientHandler;
|
||||||
ClientAcceptedHandler?.Invoke(args);
|
if (clientHandler != null)
|
||||||
|
{
|
||||||
await args.SessionTask.ConfigureAwait(false);
|
await clientHandler(adapter).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
public Task StartAsync(IMqttServerOptions options)
|
public Task StartAsync(IMqttServerOptions options)
|
||||||
{
|
{
|
||||||
@@ -43,17 +43,16 @@ namespace MQTTnet.AspNetCore
|
|||||||
var isSecureConnection = clientCertificate != null;
|
var isSecureConnection = clientCertificate != null;
|
||||||
clientCertificate?.Dispose();
|
clientCertificate?.Dispose();
|
||||||
|
|
||||||
var writer = new SpanBasedMqttPacketWriter();
|
var clientHandler = ClientHandler;
|
||||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
if (clientHandler != null)
|
||||||
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection);
|
|
||||||
var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter)));
|
|
||||||
|
|
||||||
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(channelAdapter);
|
|
||||||
ClientAcceptedHandler?.Invoke(eventArgs);
|
|
||||||
|
|
||||||
if (eventArgs.SessionTask != null)
|
|
||||||
{
|
{
|
||||||
await eventArgs.SessionTask.ConfigureAwait(false);
|
var writer = new SpanBasedMqttPacketWriter();
|
||||||
|
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||||
|
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection);
|
||||||
|
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter))))
|
||||||
|
{
|
||||||
|
await clientHandler(channelAdapter).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using MQTTnet.Exceptions;
|
||||||
|
using MQTTnet.Protocol;
|
||||||
|
|
||||||
|
namespace MQTTnet
|
||||||
|
{
|
||||||
|
public class TopicFilterBuilder
|
||||||
|
{
|
||||||
|
private MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
|
||||||
|
private string _topic;
|
||||||
|
|
||||||
|
public TopicFilterBuilder WithTopic(string topic)
|
||||||
|
{
|
||||||
|
_topic = topic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicFilterBuilder WithQualityOfServiceLevel(MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||||
|
{
|
||||||
|
_qualityOfServiceLevel = qualityOfServiceLevel;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicFilterBuilder WithAtLeastOnceQoS()
|
||||||
|
{
|
||||||
|
_qualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicFilterBuilder WithAtMostOnceQoS()
|
||||||
|
{
|
||||||
|
_qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicFilterBuilder WithExactlyOnceQoS()
|
||||||
|
{
|
||||||
|
_qualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicFilter Build()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_topic))
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException("Topic is not set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TopicFilter { Topic = _topic, QualityOfServiceLevel = _qualityOfServiceLevel };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,9 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public RetainedApplicationMessagesModel RetainedApplicationMessages { get; set; } = new RetainedApplicationMessagesModel();
|
public RetainedApplicationMessagesModel RetainedApplicationMessages { get; set; } = new RetainedApplicationMessagesModel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables the MQTTnet internal logging.
|
||||||
|
/// </summary>
|
||||||
public bool EnableDebugLogging { get; set; } = false;
|
public bool EnableDebugLogging { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,13 +60,13 @@ namespace MQTTnet.Server.Configuration
|
|||||||
{
|
{
|
||||||
if (IPv4 == "*")
|
if (IPv4 == "*")
|
||||||
{
|
{
|
||||||
address = IPAddress.Parse("0.0.0.0");
|
address = IPAddress.Any;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IPv4 == "localhost")
|
if (IPv4 == "localhost")
|
||||||
{
|
{
|
||||||
address = IPAddress.Parse("127.0.0.1");
|
address = IPAddress.Loopback;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,10 +81,8 @@ namespace MQTTnet.Server.Configuration
|
|||||||
address = ip;
|
address = ip;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw new System.Exception($"Could not parse IPv4 address: {IPv4}");
|
||||||
throw new System.Exception($"Could not parse IPv4 address: {IPv4}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -95,13 +93,13 @@ namespace MQTTnet.Server.Configuration
|
|||||||
{
|
{
|
||||||
if (IPv6 == "*")
|
if (IPv6 == "*")
|
||||||
{
|
{
|
||||||
address = IPAddress.Parse("::");
|
address = IPAddress.IPv6Any;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IPv6 == "localhost")
|
if (IPv6 == "localhost")
|
||||||
{
|
{
|
||||||
address = IPAddress.Parse("::1");
|
address = IPAddress.IPv6Loopback;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +114,8 @@ namespace MQTTnet.Server.Configuration
|
|||||||
address = ip;
|
address = ip;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw new System.Exception($"Could not parse IPv6 address: {IPv6}");
|
||||||
throw new System.Exception($"Could not parse IPv6 address: {IPv6}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,6 +152,7 @@ namespace MQTTnet.Server.Mqtt
|
|||||||
if (_settings.TcpEndPoint.Enabled)
|
if (_settings.TcpEndPoint.Enabled)
|
||||||
{
|
{
|
||||||
options.WithDefaultEndpoint();
|
options.WithDefaultEndpoint();
|
||||||
|
|
||||||
if (_settings.TcpEndPoint.TryReadIPv4(out var address4))
|
if (_settings.TcpEndPoint.TryReadIPv4(out var address4))
|
||||||
{
|
{
|
||||||
options.WithDefaultEndpointBoundIPAddress(address4);
|
options.WithDefaultEndpointBoundIPAddress(address4);
|
||||||
|
|||||||
@@ -18,14 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
"TcpEndPoint": {
|
"TcpEndPoint": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"IPv4": "localhost",
|
"IPv4": "*",
|
||||||
"IPv6": "localhost",
|
"IPv6": "*",
|
||||||
"Port": 1883
|
"Port": 1883
|
||||||
},
|
},
|
||||||
"EncryptedTcpEndPoint": {
|
"EncryptedTcpEndPoint": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
"IPv4": "localhost",
|
"IPv4": "*",
|
||||||
"IPv6": "localhost",
|
"IPv6": "*",
|
||||||
"Port": 8883,
|
"Port": 8883,
|
||||||
"CertificatePath": "/absolute/path/to/pfx"
|
"CertificatePath": "/absolute/path/to/pfx"
|
||||||
},
|
},
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"Filename": "RetainedApplicationMessages.json",
|
"Filename": "RetainedApplicationMessages.json",
|
||||||
"WriteInterval": 10 // In seconds.
|
"WriteInterval": 10 // In seconds.
|
||||||
},
|
},
|
||||||
"EnableDebugLogging": false
|
"EnableDebugLogging": true
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace MQTTnet.Adapter
|
|||||||
{
|
{
|
||||||
public interface IMqttServerAdapter : IDisposable
|
public interface IMqttServerAdapter : IDisposable
|
||||||
{
|
{
|
||||||
Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
Task StartAsync(IMqttServerOptions options);
|
Task StartAsync(IMqttServerOptions options);
|
||||||
Task StopAsync();
|
Task StopAsync();
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MQTTnet.Adapter
|
|
||||||
{
|
|
||||||
public class MqttServerAdapterClientAcceptedEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter channelAdapter)
|
|
||||||
{
|
|
||||||
ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMqttChannelAdapter ChannelAdapter { get; }
|
|
||||||
|
|
||||||
public Task SessionTask { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@ namespace MQTTnet.Implementations
|
|||||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
public async Task StartAsync(IMqttServerOptions options)
|
public async Task StartAsync(IMqttServerOptions options)
|
||||||
{
|
{
|
||||||
@@ -39,7 +39,7 @@ namespace MQTTnet.Implementations
|
|||||||
_listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay;
|
_listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay;
|
||||||
_listener.Control.KeepAlive = true;
|
_listener.Control.KeepAlive = true;
|
||||||
_listener.Control.QualityOfService = SocketQualityOfService.LowLatency;
|
_listener.Control.QualityOfService = SocketQualityOfService.LowLatency;
|
||||||
_listener.ConnectionReceived += AcceptDefaultEndpointConnectionsAsync;
|
_listener.ConnectionReceived += OnConnectionReceivedAsync;
|
||||||
|
|
||||||
await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket);
|
await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket);
|
||||||
}
|
}
|
||||||
@@ -54,30 +54,51 @@ namespace MQTTnet.Implementations
|
|||||||
{
|
{
|
||||||
if (_listener != null)
|
if (_listener != null)
|
||||||
{
|
{
|
||||||
_listener.ConnectionReceived -= AcceptDefaultEndpointConnectionsAsync;
|
_listener.ConnectionReceived -= OnConnectionReceivedAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
_listener?.Dispose();
|
|
||||||
_listener = null;
|
|
||||||
|
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
StopAsync().GetAwaiter().GetResult();
|
_listener?.Dispose();
|
||||||
|
_listener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcceptDefaultEndpointConnectionsAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
|
private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger);
|
var clientHandler = ClientHandler;
|
||||||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
if (clientHandler != null)
|
||||||
|
{
|
||||||
|
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger))
|
||||||
|
{
|
||||||
|
await clientHandler(clientAdapter).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_logger.Error(exception, "Error while accepting connection at default endpoint.");
|
if (exception is ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Error(exception, "Error while handling client connection.");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
args.Socket.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error(exception, "Error while cleaning up client connection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace MQTTnet.Implementations
|
|||||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
public Task StartAsync(IMqttServerOptions options)
|
public Task StartAsync(IMqttServerOptions options)
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@ namespace MQTTnet.Implementations
|
|||||||
_cancellationTokenSource.Token,
|
_cancellationTokenSource.Token,
|
||||||
_logger)
|
_logger)
|
||||||
{
|
{
|
||||||
ClientAcceptedHandler = OnClientAccepted
|
ClientHandler = OnClientAcceptedAsync
|
||||||
};
|
};
|
||||||
|
|
||||||
listenerV4.Start();
|
listenerV4.Start();
|
||||||
@@ -105,7 +105,7 @@ namespace MQTTnet.Implementations
|
|||||||
_cancellationTokenSource.Token,
|
_cancellationTokenSource.Token,
|
||||||
_logger)
|
_logger)
|
||||||
{
|
{
|
||||||
ClientAcceptedHandler = OnClientAccepted
|
ClientHandler = OnClientAcceptedAsync
|
||||||
};
|
};
|
||||||
|
|
||||||
listenerV6.Start();
|
listenerV6.Start();
|
||||||
@@ -113,9 +113,15 @@ namespace MQTTnet.Implementations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
|
private Task OnClientAcceptedAsync(IMqttChannelAdapter channelAdapter)
|
||||||
{
|
{
|
||||||
ClientAcceptedHandler?.Invoke(eventArgs);
|
var clientHandler = ClientHandler;
|
||||||
|
if (clientHandler == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientHandler(channelAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace MQTTnet.Implementations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
@@ -97,11 +97,14 @@ namespace MQTTnet.Implementations
|
|||||||
private async Task TryHandleClientConnectionAsync(Socket clientSocket)
|
private async Task TryHandleClientConnectionAsync(Socket clientSocket)
|
||||||
{
|
{
|
||||||
Stream stream = null;
|
Stream stream = null;
|
||||||
|
EndPoint remoteEndPoint = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
remoteEndPoint = clientSocket.RemoteEndPoint;
|
||||||
|
|
||||||
_logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
|
_logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
|
||||||
clientSocket.RemoteEndPoint,
|
remoteEndPoint,
|
||||||
_socket.LocalEndPoint,
|
_socket.LocalEndPoint,
|
||||||
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
|
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
|
||||||
|
|
||||||
@@ -116,8 +119,14 @@ namespace MQTTnet.Implementations
|
|||||||
stream = sslStream;
|
stream = sslStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger);
|
var clientHandler = ClientHandler;
|
||||||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
if (clientHandler != null)
|
||||||
|
{
|
||||||
|
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger))
|
||||||
|
{
|
||||||
|
await clientHandler(clientAdapter).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -127,20 +136,29 @@ namespace MQTTnet.Implementations
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exception is SocketException socketException && socketException.SocketErrorCode == SocketError.OperationAborted)
|
if (exception is SocketException socketException &&
|
||||||
|
socketException.SocketErrorCode == SocketError.OperationAborted)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Error(exception, "Error while handling client connection.");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Dispose already allocated resources.
|
|
||||||
stream?.Dispose();
|
stream?.Dispose();
|
||||||
clientSocket?.Dispose();
|
clientSocket?.Dispose();
|
||||||
|
|
||||||
|
_logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.",
|
||||||
|
remoteEndPoint,
|
||||||
|
_socket.LocalEndPoint,
|
||||||
|
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
|
||||||
}
|
}
|
||||||
catch (Exception disposeException)
|
catch (Exception disposeException)
|
||||||
{
|
{
|
||||||
_logger.Error(disposeException, "Error while cleanup of broken connection.");
|
_logger.Error(disposeException, "Error while cleaning up client connection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ namespace MQTTnet.Server
|
|||||||
private readonly IMqttNetChildLogger _logger;
|
private readonly IMqttNetChildLogger _logger;
|
||||||
private readonly IMqttServerOptions _serverOptions;
|
private readonly IMqttServerOptions _serverOptions;
|
||||||
|
|
||||||
private Task<MqttClientDisconnectType> _packageReceiverTask;
|
|
||||||
private readonly IMqttChannelAdapter _channelAdapter;
|
private readonly IMqttChannelAdapter _channelAdapter;
|
||||||
private readonly IMqttDataConverter _dataConverter;
|
private readonly IMqttDataConverter _dataConverter;
|
||||||
private readonly string _endpoint;
|
private readonly string _endpoint;
|
||||||
private readonly MqttConnectPacket _connectPacket;
|
private readonly MqttConnectPacket _connectPacket;
|
||||||
|
|
||||||
|
private Task<MqttClientDisconnectType> _packageReceiverTask;
|
||||||
private DateTime _lastPacketReceivedTimestamp;
|
private DateTime _lastPacketReceivedTimestamp;
|
||||||
private DateTime _lastNonKeepAlivePacketReceivedTimestamp;
|
private DateTime _lastNonKeepAlivePacketReceivedTimestamp;
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ namespace MQTTnet.Server
|
|||||||
StopInternal();
|
StopInternal();
|
||||||
|
|
||||||
var task = _packageReceiverTask;
|
var task = _packageReceiverTask;
|
||||||
if (task != null && !task.IsCompleted)
|
if (task != null)
|
||||||
{
|
{
|
||||||
await task.ConfigureAwait(false);
|
await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -103,13 +103,6 @@ namespace MQTTnet.Server
|
|||||||
status.BytesReceived = _channelAdapter.BytesReceived;
|
status.BytesReceived = _channelAdapter.BytesReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void ClearPendingApplicationMessages()
|
|
||||||
//{
|
|
||||||
// Session.ApplicationMessagesQueue.Clear();
|
|
||||||
|
|
||||||
// //_applicationMessagesQueue.Clear();
|
|
||||||
//}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_cancellationToken.Dispose();
|
_cancellationToken.Dispose();
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task HandleConnectionAsync(IMqttChannelAdapter clientAdapter)
|
public Task HandleClientAsync(IMqttChannelAdapter clientAdapter)
|
||||||
{
|
{
|
||||||
return HandleConnectionAsync(clientAdapter, _cancellationToken);
|
return HandleClientAsync(clientAdapter, _cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IList<IMqttClientStatus>> GetClientStatusAsync()
|
public Task<IList<IMqttClientStatus>> GetClientStatusAsync()
|
||||||
@@ -221,7 +221,7 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleConnectionAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
|
private async Task HandleClientAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var disconnectType = MqttClientDisconnectType.NotClean;
|
var disconnectType = MqttClientDisconnectType.NotClean;
|
||||||
var clientId = string.Empty;
|
var clientId = string.Empty;
|
||||||
@@ -376,10 +376,6 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
_logger.Error(exception, "Error while disconnecting client channel.");
|
_logger.Error(exception, "Error while disconnecting client channel.");
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
channelAdapter.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
foreach (var adapter in _adapters)
|
foreach (var adapter in _adapters)
|
||||||
{
|
{
|
||||||
adapter.ClientAcceptedHandler = OnClientAccepted;
|
adapter.ClientHandler = OnHandleClient;
|
||||||
await adapter.StartAsync(Options).ConfigureAwait(false);
|
await adapter.StartAsync(Options).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
foreach (var adapter in _adapters)
|
foreach (var adapter in _adapters)
|
||||||
{
|
{
|
||||||
adapter.ClientAcceptedHandler = null;
|
adapter.ClientHandler = null;
|
||||||
await adapter.StopAsync().ConfigureAwait(false);
|
await adapter.StopAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,9 +184,9 @@ namespace MQTTnet.Server
|
|||||||
return _retainedMessagesManager?.ClearMessagesAsync();
|
return _retainedMessagesManager?.ClearMessagesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
|
private Task OnHandleClient(IMqttChannelAdapter channelAdapter)
|
||||||
{
|
{
|
||||||
eventArgs.SessionTask = _clientSessionsManager.HandleConnectionAsync(eventArgs.ChannelAdapter);
|
return _clientSessionsManager.HandleClientAsync(channelAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,16 @@ namespace MQTTnet.Benchmarks
|
|||||||
{
|
{
|
||||||
var factory = new MqttFactory();
|
var factory = new MqttFactory();
|
||||||
var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
|
var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
|
||||||
tcpServer.ClientAcceptedHandler += args => _serverChannel = (IMqttChannel)args.ChannelAdapter.GetType().GetField("_channel", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(args.ChannelAdapter);
|
tcpServer.ClientHandler += args =>
|
||||||
|
{
|
||||||
|
_serverChannel =
|
||||||
|
(IMqttChannel)args.GetType().GetField("_channel",
|
||||||
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
||||||
|
.GetValue(args);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
_mqttServer = factory.CreateMqttServer(new[] { tcpServer }, new MqttNetLogger());
|
_mqttServer = factory.CreateMqttServer(new[] { tcpServer }, new MqttNetLogger());
|
||||||
|
|
||||||
var serverOptions = new MqttServerOptionsBuilder().Build();
|
var serverOptions = new MqttServerOptionsBuilder().Build();
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MQTTnet.Adapter;
|
|
||||||
using MQTTnet.Client;
|
|
||||||
using MQTTnet.Client.Options;
|
|
||||||
using MQTTnet.Diagnostics;
|
|
||||||
using MQTTnet.Server;
|
|
||||||
|
|
||||||
namespace MQTTnet.Tests.Mockups
|
|
||||||
{
|
|
||||||
public class TestMqttServerAdapter : IMqttServerAdapter
|
|
||||||
{
|
|
||||||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
|
|
||||||
|
|
||||||
public async Task<IMqttClient> ConnectTestClient(string clientId, MqttApplicationMessage willMessage = null)
|
|
||||||
{
|
|
||||||
var adapterA = new TestMqttCommunicationAdapter();
|
|
||||||
var adapterB = new TestMqttCommunicationAdapter();
|
|
||||||
adapterA.Partner = adapterB;
|
|
||||||
adapterB.Partner = adapterA;
|
|
||||||
|
|
||||||
var client = new MqttClient(
|
|
||||||
new TestMqttCommunicationAdapterFactory(adapterA),
|
|
||||||
new MqttNetLogger());
|
|
||||||
|
|
||||||
FireClientAcceptedEvent(adapterB);
|
|
||||||
|
|
||||||
var options = new MqttClientOptions
|
|
||||||
{
|
|
||||||
ClientId = clientId,
|
|
||||||
WillMessage = willMessage,
|
|
||||||
ChannelOptions = new MqttClientTcpOptions()
|
|
||||||
};
|
|
||||||
|
|
||||||
await client.ConnectAsync(options);
|
|
||||||
SpinWait.SpinUntil(() => client.IsConnected);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FireClientAcceptedEvent(IMqttChannelAdapter adapter)
|
|
||||||
{
|
|
||||||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(adapter));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(IMqttServerOptions options)
|
|
||||||
{
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user