From b7e92e1cd706715a793fd31f2b751529b2b7b4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Foidl?= Date: Tue, 4 Jan 2022 14:57:46 +0100 Subject: [PATCH 1/2] Elide repeated Action-delegate allocation by caching it Here C# compiler has too little knowledge about the usage of the delegate, we know better so cache it on our own to avoid the repeated allocation. --- .../MQTTnet/Implementations/CrossPlatformSocket.cs | 10 ++++++++-- Source/MQTTnet/Implementations/MqttTcpChannel.cs | 14 ++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs index 18d2d8927..86e0be1b7 100644 --- a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs +++ b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using System.Net.Sockets; @@ -11,12 +11,14 @@ namespace MQTTnet.Implementations public sealed class CrossPlatformSocket : IDisposable { readonly Socket _socket; + readonly Action _socketDisposeAction; NetworkStream _networkStream; public CrossPlatformSocket(AddressFamily addressFamily) { _socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); + _socketDisposeAction = _socket.Dispose; } public CrossPlatformSocket() @@ -24,12 +26,16 @@ public CrossPlatformSocket() // Having this constructor is important because avoiding the address family as parameter // will make use of dual mode in the .net framework. _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + + _socketDisposeAction = _socket.Dispose; } public CrossPlatformSocket(Socket socket) { _socket = socket ?? throw new ArgumentNullException(nameof(socket)); _networkStream = new NetworkStream(socket, true); + + _socketDisposeAction = _socket.Dispose; } public bool NoDelay @@ -112,7 +118,7 @@ public async Task ConnectAsync(string host, int port, CancellationToken cancella _networkStream?.Dispose(); // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(() => _socket.Dispose())) + using (cancellationToken.Register(_socketDisposeAction)) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index 4cb58ec88..eed869a0b 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -18,10 +18,16 @@ public sealed class MqttTcpChannel : IMqttChannel { readonly IMqttClientOptions _clientOptions; readonly MqttClientTcpOptions _tcpOptions; + readonly Action _disposeAction; Stream _stream; - public MqttTcpChannel(IMqttClientOptions clientOptions) + public MqttTcpChannel() + { + _disposeAction = Dispose; + } + + public MqttTcpChannel(IMqttClientOptions clientOptions) : this() { _clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions)); _tcpOptions = (MqttClientTcpOptions)clientOptions.ChannelOptions; @@ -29,7 +35,7 @@ public MqttTcpChannel(IMqttClientOptions clientOptions) IsSecureConnection = clientOptions.ChannelOptions?.TlsOptions?.UseTls == true; } - public MqttTcpChannel(Stream stream, string endpoint, X509Certificate2 clientCertificate) + public MqttTcpChannel(Stream stream, string endpoint, X509Certificate2 clientCertificate) : this() { _stream = stream ?? throw new ArgumentNullException(nameof(stream)); @@ -150,7 +156,7 @@ public async Task ReadAsync(byte[] buffer, int offset, int count, Cancellat } // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(Dispose)) + using (cancellationToken.Register(_disposeAction)) { return await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } @@ -178,7 +184,7 @@ public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationT try { // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(Dispose)) + using (cancellationToken.Register(_disposeAction)) { var stream = _stream; From 74e34e327b25ac8804b59dd25a76fae313ebf645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Foidl?= Date: Tue, 4 Jan 2022 20:14:11 +0100 Subject: [PATCH 2/2] Use conditional compilation --- .../MQTTnet/Implementations/MqttTcpChannel.cs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index eed869a0b..800ab46d6 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -155,11 +155,15 @@ public async Task ReadAsync(byte[] buffer, int offset, int count, Cancellat return 0; } +#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return await stream.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); +#else // Workaround for: https://github.com/dotnet/corefx/issues/24430 using (cancellationToken.Register(_disposeAction)) { return await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } +#endif } catch (ObjectDisposedException) { @@ -183,18 +187,22 @@ public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationT try { + var stream = _stream; + + if (stream == null) + { + throw new MqttCommunicationException("The TCP connection is closed."); + } + +#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + await stream.WriteAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); +#else // Workaround for: https://github.com/dotnet/corefx/issues/24430 using (cancellationToken.Register(_disposeAction)) { - var stream = _stream; - - if (stream == null) - { - throw new MqttCommunicationException("The TCP connection is closed."); - } - await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } +#endif } catch (ObjectDisposedException) {