mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-22 12:53:04 +08:00
send multiple packages at once msg/sec from 9000 to 32000
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Core.Client;
|
||||
using MQTTnet.Core.Packets;
|
||||
@@ -12,10 +13,18 @@ namespace MQTTnet.Core.Adapter
|
||||
|
||||
Task DisconnectAsync();
|
||||
|
||||
Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout);
|
||||
Task SendPacketsAsync( TimeSpan timeout, IEnumerable<MqttBasePacket> packets );
|
||||
|
||||
Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout);
|
||||
|
||||
IMqttPacketSerializer PacketSerializer { get; }
|
||||
}
|
||||
|
||||
public static class IMqttCommunicationAdapterExtensions
|
||||
{
|
||||
public static Task SendPacketsAsync( this IMqttCommunicationAdapter adapter, TimeSpan timeout, params MqttBasePacket[] packets )
|
||||
{
|
||||
return adapter.SendPacketsAsync( timeout, packets );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -34,13 +35,18 @@ namespace MQTTnet.Core.Adapter
|
||||
return _channel.DisconnectAsync();
|
||||
}
|
||||
|
||||
public Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout)
|
||||
public async Task SendPacketsAsync( TimeSpan timeout, IEnumerable<MqttBasePacket> packets )
|
||||
{
|
||||
MqttTrace.Information(nameof(MqttChannelCommunicationAdapter), "TX >>> {0} [Timeout={1}]", packet, timeout);
|
||||
foreach (var packet in packets )
|
||||
{
|
||||
MqttTrace.Information( nameof( MqttChannelCommunicationAdapter ), "TX >>> {0} [Timeout={1}]", packet, timeout );
|
||||
|
||||
var writeBuffer = PacketSerializer.Serialize(packet);
|
||||
_sendTask = SendAsync( writeBuffer );
|
||||
return _sendTask.TimeoutAfter(timeout);
|
||||
var writeBuffer = PacketSerializer.Serialize(packet);
|
||||
_sendTask = SendAsync( writeBuffer );
|
||||
}
|
||||
|
||||
await _sendTask.ConfigureAwait( false );
|
||||
await _channel.SendStream.FlushAsync().TimeoutAfter( timeout ).ConfigureAwait( false );
|
||||
}
|
||||
|
||||
private Task _sendTask = Task.FromResult(0); // this task is used to prevent overlapping write
|
||||
@@ -48,7 +54,7 @@ namespace MQTTnet.Core.Adapter
|
||||
private async Task SendAsync(byte[] buffer)
|
||||
{
|
||||
await _sendTask.ConfigureAwait(false);
|
||||
await _channel.Stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait( false );
|
||||
await _channel.SendStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait( false );
|
||||
}
|
||||
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout)
|
||||
@@ -76,7 +82,7 @@ namespace MQTTnet.Core.Adapter
|
||||
|
||||
private async Task<Tuple<MqttPacketHeader, MemoryStream>> ReceiveAsync()
|
||||
{
|
||||
var header = MqttPacketReader.ReadHeaderFromSource(_channel.Stream);
|
||||
var header = MqttPacketReader.ReadHeaderFromSource(_channel.ReceiveStream);
|
||||
|
||||
MemoryStream body = null;
|
||||
if (header.BodyLength > 0)
|
||||
@@ -85,7 +91,7 @@ namespace MQTTnet.Core.Adapter
|
||||
var readBuffer = new byte[header.BodyLength];
|
||||
do
|
||||
{
|
||||
var read = await _channel.Stream.ReadAsync(readBuffer, totalRead, header.BodyLength - totalRead)
|
||||
var read = await _channel.ReceiveStream.ReadAsync(readBuffer, totalRead, header.BodyLength - totalRead)
|
||||
.ConfigureAwait( false );
|
||||
totalRead += read;
|
||||
} while (totalRead < header.BodyLength);
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace MQTTnet.Core.Channel
|
||||
|
||||
Task DisconnectAsync();
|
||||
|
||||
Stream Stream { get; }
|
||||
Stream SendStream { get; }
|
||||
|
||||
Stream ReceiveStream { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,18 @@ namespace MQTTnet.Core.Client
|
||||
|
||||
Task ConnectAsync(MqttApplicationMessage willApplicationMessage = null);
|
||||
Task DisconnectAsync();
|
||||
Task PublishAsync(MqttApplicationMessage applicationMessage);
|
||||
Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages);
|
||||
Task<IList<MqttSubscribeResult>> SubscribeAsync(IList<TopicFilter> topicFilters);
|
||||
Task<IList<MqttSubscribeResult>> SubscribeAsync(params TopicFilter[] topicFilters);
|
||||
Task Unsubscribe(IList<string> topicFilters);
|
||||
Task Unsubscribe(params string[] topicFilters);
|
||||
}
|
||||
|
||||
public static class IMqttClientExtensions
|
||||
{
|
||||
public static Task PublishAsync( this IMqttClient client, params MqttApplicationMessage[] applicationMessages )
|
||||
{
|
||||
return client.PublishAsync( applicationMessages );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,32 +161,43 @@ namespace MQTTnet.Core.Client
|
||||
return SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket);
|
||||
}
|
||||
|
||||
public Task PublishAsync(MqttApplicationMessage applicationMessage)
|
||||
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||
{
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
ThrowIfNotConnected();
|
||||
|
||||
var publishPacket = applicationMessage.ToPublishPacket();
|
||||
var publishPackets = applicationMessages.Select(m => m.ToPublishPacket());
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||
foreach (var qosGroup in publishPackets.GroupBy(p => p.QualityOfServiceLevel))
|
||||
{
|
||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||
return SendAsync(publishPacket);
|
||||
var qosPackets = qosGroup.ToArray();
|
||||
switch ( qosGroup.Key )
|
||||
{
|
||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||
await _adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, qosPackets);
|
||||
break;
|
||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||
{
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||
{
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
await PublishExactlyOncePacketAsync( publishPacket );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
return SendAndReceiveAsync<MqttPubAckPacket>(publishPacket);
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
return PublishExactlyOncePacketAsync(publishPacket);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private async Task PublishExactlyOncePacketAsync(MqttBasePacket publishPacket)
|
||||
@@ -312,14 +323,13 @@ namespace MQTTnet.Core.Client
|
||||
|
||||
private Task SendAsync(MqttBasePacket packet)
|
||||
{
|
||||
return _adapter.SendPacketAsync(packet, _options.DefaultCommunicationTimeout);
|
||||
return _adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, packet);
|
||||
}
|
||||
|
||||
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket
|
||||
{
|
||||
await _adapter.SendPacketAsync(requestPacket, _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
|
||||
return (TResponsePacket)await _packetDispatcher.WaitForPacketAsync(requestPacket, typeof(TResponsePacket), _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
await _adapter.SendPacketsAsync( _options.DefaultCommunicationTimeout, requestPacket ).ConfigureAwait(false);
|
||||
return (TResponsePacket)await _packetDispatcher.WaitForPacketAsync(requestPacket, typeof( TResponsePacket ), _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private ushort GetNewPacketIdentifier()
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace MQTTnet.Core.Server
|
||||
}
|
||||
|
||||
publishPacketContext.PublishPacket.Dup = publishPacketContext.SendTries > 0;
|
||||
await _adapter.SendPacketAsync(publishPacketContext.PublishPacket, _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
await _adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, publishPacketContext.PublishPacket).ConfigureAwait(false);
|
||||
|
||||
publishPacketContext.IsSent = true;
|
||||
}
|
||||
|
||||
@@ -103,12 +103,12 @@ namespace MQTTnet.Core.Server
|
||||
{
|
||||
if (packet is MqttSubscribePacket subscribePacket)
|
||||
{
|
||||
return Adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _subscriptionsManager.Subscribe(subscribePacket));
|
||||
}
|
||||
|
||||
if (packet is MqttUnsubscribePacket unsubscribePacket)
|
||||
{
|
||||
return Adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _subscriptionsManager.Unsubscribe(unsubscribePacket));
|
||||
}
|
||||
|
||||
if (packet is MqttPublishPacket publishPacket)
|
||||
@@ -123,7 +123,7 @@ namespace MQTTnet.Core.Server
|
||||
|
||||
if (packet is MqttPubRecPacket pubRecPacket)
|
||||
{
|
||||
return Adapter.SendPacketAsync(pubRecPacket.CreateResponse<MqttPubRelPacket>(), _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, pubRecPacket.CreateResponse<MqttPubRelPacket>());
|
||||
}
|
||||
|
||||
if (packet is MqttPubAckPacket || packet is MqttPubCompPacket)
|
||||
@@ -134,7 +134,7 @@ namespace MQTTnet.Core.Server
|
||||
|
||||
if (packet is MqttPingReqPacket)
|
||||
{
|
||||
return Adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttPingRespPacket());
|
||||
}
|
||||
|
||||
if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
|
||||
@@ -160,7 +160,7 @@ namespace MQTTnet.Core.Server
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
_publishPacketReceivedCallback(this, publishPacket);
|
||||
return Adapter.SendPacketAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }, _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||
@@ -173,7 +173,7 @@ namespace MQTTnet.Core.Server
|
||||
|
||||
_publishPacketReceivedCallback(this, publishPacket);
|
||||
|
||||
return Adapter.SendPacketAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }, _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||
}
|
||||
|
||||
throw new MqttCommunicationException("Received a not supported QoS level.");
|
||||
@@ -186,7 +186,7 @@ namespace MQTTnet.Core.Server
|
||||
_unacknowledgedPublishPackets.Remove(pubRelPacket.PacketIdentifier);
|
||||
}
|
||||
|
||||
return Adapter.SendPacketAsync(new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }, _options.DefaultCommunicationTimeout);
|
||||
return Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,21 +40,21 @@ namespace MQTTnet.Core.Server
|
||||
var connectReturnCode = ValidateConnection(connectPacket);
|
||||
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
|
||||
{
|
||||
await eventArgs.ClientAdapter.SendPacketAsync(new MqttConnAckPacket
|
||||
await eventArgs.ClientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode
|
||||
}, _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var clientSession = GetOrCreateClientSession(connectPacket);
|
||||
|
||||
await eventArgs.ClientAdapter.SendPacketAsync(new MqttConnAckPacket
|
||||
await eventArgs.ClientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode,
|
||||
IsSessionPresent = clientSession.IsExistingSession
|
||||
}, _options.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
await clientSession.Session.RunAsync(eventArgs.Identifier, connectPacket.WillMessage, eventArgs.ClientAdapter).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user