fixed parallel writesrelease/3.x.x
@@ -10,7 +10,9 @@ | |||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> | <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> | ||||
<requireLicenseAcceptance>false</requireLicenseAcceptance> | <requireLicenseAcceptance>false</requireLicenseAcceptance> | ||||
<description>This is a support library to integrate MQTTnet into AspNetCore.</description> | <description>This is a support library to integrate MQTTnet into AspNetCore.</description> | ||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> | |||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). | |||||
* fixed concurrent sends with Aspnetcore.Connections.Abstractions based transport | |||||
</releaseNotes> | |||||
<copyright>Copyright Christian Kratky 2016-2018</copyright> | <copyright>Copyright Christian Kratky 2016-2018</copyright> | ||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> | <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> | ||||
<dependencies> | <dependencies> | ||||
@@ -27,6 +27,8 @@ namespace MQTTnet.AspNetCore | |||||
public event EventHandler ReadingPacketStarted; | public event EventHandler ReadingPacketStarted; | ||||
public event EventHandler ReadingPacketCompleted; | public event EventHandler ReadingPacketCompleted; | ||||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); | |||||
public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) | public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) | ||||
{ | { | ||||
if (Connection is TcpConnection tcp && !tcp.IsConnected) | if (Connection is TcpConnection tcp && !tcp.IsConnected) | ||||
@@ -105,10 +107,20 @@ namespace MQTTnet.AspNetCore | |||||
return null; | return null; | ||||
} | } | ||||
public Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken) | |||||
public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken) | |||||
{ | { | ||||
var buffer = PacketSerializer.Serialize(packet); | |||||
return Connection.Transport.Output.WriteAsync(buffer.AsMemory(), cancellationToken).AsTask(); | |||||
var buffer = PacketSerializer.Serialize(packet).AsMemory(); | |||||
var output = Connection.Transport.Output; | |||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); | |||||
try | |||||
{ | |||||
await output.WriteAsync(buffer, cancellationToken); | |||||
} | |||||
finally | |||||
{ | |||||
_writerSemaphore.Release(); | |||||
} | |||||
} | } | ||||
public void Dispose() | public void Dispose() | ||||
@@ -2,8 +2,10 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
using MQTTnet.AspNetCore.Tests.Mockups; | using MQTTnet.AspNetCore.Tests.Mockups; | ||||
using MQTTnet.Exceptions; | using MQTTnet.Exceptions; | ||||
using MQTTnet.Packets; | |||||
using MQTTnet.Serializer; | using MQTTnet.Serializer; | ||||
using System; | using System; | ||||
using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
@@ -25,5 +27,25 @@ namespace MQTTnet.AspNetCore.Tests | |||||
await Assert.ThrowsExceptionAsync<MqttCommunicationException>(() => ctx.ReceivePacketAsync(TimeSpan.FromSeconds(1), CancellationToken.None)); | await Assert.ThrowsExceptionAsync<MqttCommunicationException>(() => ctx.ReceivePacketAsync(TimeSpan.FromSeconds(1), CancellationToken.None)); | ||||
} | } | ||||
[TestMethod] | |||||
public async Task TestParallelWrites() | |||||
{ | |||||
var serializer = new MqttPacketSerializer { }; | |||||
var pipe = new DuplexPipeMockup(); | |||||
var connection = new DefaultConnectionContext(); | |||||
connection.Transport = pipe; | |||||
var ctx = new MqttConnectionContext(serializer, connection); | |||||
var tasks = Enumerable.Range(1, 10).Select(_ => Task.Run(async () => | |||||
{ | |||||
for (int i = 0; i < 100; i++) | |||||
{ | |||||
await ctx.SendPacketAsync(new MqttPublishPacket(), CancellationToken.None).ConfigureAwait(false); | |||||
} | |||||
})); | |||||
await Task.WhenAll(tasks).ConfigureAwait(false); | |||||
} | |||||
} | } | ||||
} | } |