mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-28 17:22:37 +08:00
Allow disabling of packet fragmentation (#1709)
* Add compatibility option for AWS * Fix UWP build * Fix comment in MqttClientOptions (#1706) * Refactor naming * Fix wrong option value --------- Co-authored-by: Michi <michael@volz.dev>
This commit is contained in:
@@ -27,18 +27,15 @@ namespace MQTTnet.Adapter
|
||||
readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
|
||||
readonly MqttPacketInspector _packetInspector;
|
||||
|
||||
readonly byte[] _singleByteBuffer = new byte[1];
|
||||
|
||||
readonly AsyncLock _syncRoot = new AsyncLock();
|
||||
|
||||
Statistics _statistics; // mutable struct, don't make readonly!
|
||||
Statistics _statistics; // mutable struct, don't make readonly!
|
||||
|
||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, MqttPacketInspector packetInspector, IMqttNetLogger logger)
|
||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetLogger logger)
|
||||
{
|
||||
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
_packetInspector = packetInspector;
|
||||
|
||||
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
|
||||
|
||||
@@ -64,6 +61,10 @@ namespace MQTTnet.Adapter
|
||||
|
||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||
|
||||
public MqttPacketInspector PacketInspector { get; set; }
|
||||
|
||||
public bool AllowPacketFragmentation { get; set; } = true;
|
||||
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -126,7 +127,7 @@ namespace MQTTnet.Adapter
|
||||
|
||||
try
|
||||
{
|
||||
_packetInspector?.BeginReceivePacket();
|
||||
PacketInspector?.BeginReceivePacket();
|
||||
|
||||
ReceivedMqttPacket receivedPacket;
|
||||
var receivedPacketTask = ReceiveAsync(cancellationToken);
|
||||
@@ -144,7 +145,7 @@ namespace MQTTnet.Adapter
|
||||
return null;
|
||||
}
|
||||
|
||||
_packetInspector?.EndReceivePacket();
|
||||
PacketInspector?.EndReceivePacket();
|
||||
|
||||
Interlocked.Add(ref _statistics._bytesSent, receivedPacket.TotalLength);
|
||||
|
||||
@@ -180,7 +181,10 @@ namespace MQTTnet.Adapter
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResetStatistics() => _statistics.Reset();
|
||||
public void ResetStatistics()
|
||||
{
|
||||
_statistics.Reset();
|
||||
}
|
||||
|
||||
public async Task SendPacketAsync(MqttPacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -197,18 +201,18 @@ namespace MQTTnet.Adapter
|
||||
try
|
||||
{
|
||||
var packetBuffer = PacketFormatterAdapter.Encode(packet);
|
||||
_packetInspector?.BeginSendPacket(packetBuffer);
|
||||
PacketInspector?.BeginSendPacket(packetBuffer);
|
||||
|
||||
_logger.Verbose("TX ({0} bytes) >>> {1}", packetBuffer.Length, packet);
|
||||
|
||||
if (packetBuffer.Payload.Count > 0)
|
||||
|
||||
if (packetBuffer.Payload.Count == 0 || !AllowPacketFragmentation)
|
||||
{
|
||||
await _channel.WriteAsync(packetBuffer.Packet, false, cancellationToken).ConfigureAwait(false);
|
||||
await _channel.WriteAsync(packetBuffer.Payload, true, cancellationToken).ConfigureAwait(false);
|
||||
await _channel.WriteAsync(packetBuffer.Join(), true, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _channel.WriteAsync(packetBuffer.Packet, true, cancellationToken).ConfigureAwait(false);
|
||||
await _channel.WriteAsync(packetBuffer.Packet, false, cancellationToken).ConfigureAwait(false);
|
||||
await _channel.WriteAsync(packetBuffer.Payload, true, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Interlocked.Add(ref _statistics._bytesReceived, packetBuffer.Length);
|
||||
@@ -270,7 +274,7 @@ namespace MQTTnet.Adapter
|
||||
return 0;
|
||||
}
|
||||
|
||||
_packetInspector?.FillReceiveBuffer(_singleByteBuffer);
|
||||
PacketInspector?.FillReceiveBuffer(_singleByteBuffer);
|
||||
|
||||
encodedByte = _singleByteBuffer[0];
|
||||
|
||||
@@ -309,7 +313,7 @@ namespace MQTTnet.Adapter
|
||||
{
|
||||
return ReadFixedHeaderResult.ConnectionClosed;
|
||||
}
|
||||
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return ReadFixedHeaderResult.Canceled;
|
||||
@@ -323,7 +327,7 @@ namespace MQTTnet.Adapter
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
_packetInspector?.FillReceiveBuffer(buffer);
|
||||
PacketInspector?.FillReceiveBuffer(buffer);
|
||||
|
||||
var hasRemainingLength = buffer[1] != 0;
|
||||
if (!hasRemainingLength)
|
||||
@@ -407,7 +411,7 @@ namespace MQTTnet.Adapter
|
||||
bodyOffset += readBytes;
|
||||
} while (bodyOffset < bodyLength);
|
||||
|
||||
_packetInspector?.FillReceiveBuffer(body);
|
||||
PacketInspector?.FillReceiveBuffer(body);
|
||||
|
||||
var bodySegment = new ArraySegment<byte>(body, 0, bodyLength);
|
||||
return new ReceivedMqttPacket(fixedHeader.Flags, bodySegment, fixedHeader.TotalLength);
|
||||
@@ -455,7 +459,7 @@ namespace MQTTnet.Adapter
|
||||
throw new MqttCommunicationException(exception);
|
||||
}
|
||||
|
||||
private struct Statistics
|
||||
struct Statistics
|
||||
{
|
||||
public long _bytesReceived;
|
||||
public long _bytesSent;
|
||||
|
||||
@@ -24,6 +24,14 @@ namespace MQTTnet.Client
|
||||
/// </summary>
|
||||
public string AuthenticationMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Usually the MQTT packets can be send partially. This is done by using multiple TCP packets
|
||||
/// or WebSocket frames etc. Unfortunately not all brokers (like Amazon Web Services (AWS)) do support this feature and
|
||||
/// will close the connection when receiving such packets. If such a service is used this flag must
|
||||
/// be set to _false_.
|
||||
/// </summary>
|
||||
public bool AllowPacketFragmentation { get; set; } = true;
|
||||
|
||||
public IMqttClientChannelOptions ChannelOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -214,4 +222,4 @@ namespace MQTTnet.Client
|
||||
/// </summary>
|
||||
public int WriterBufferSizeMax { get; set; } = 65535;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,10 +75,22 @@ namespace MQTTnet.Client
|
||||
_options.ChannelOptions = (IMqttClientChannelOptions)_tcpOptions ?? _webSocketOptions;
|
||||
|
||||
MqttClientOptionsValidator.ThrowIfNotSupported(_options);
|
||||
|
||||
|
||||
return _options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Usually the MQTT packets can be send partially. This is done by using multiple TCP packets
|
||||
/// or WebSocket frames etc. Unfortunately not all brokers (like Amazon Web Services (AWS)) do support this feature and
|
||||
/// will close the connection when receiving such packets. If such a service is used this flag must
|
||||
/// be set to _true_.
|
||||
/// </summary>
|
||||
public MqttClientOptionsBuilder WithoutPacketFragmentation()
|
||||
{
|
||||
_options.AllowPacketFragmentation = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithAuthentication(string method, byte[] data)
|
||||
{
|
||||
_options.AuthenticationMethod = method;
|
||||
@@ -266,7 +278,7 @@ namespace MQTTnet.Client
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public MqttClientOptionsBuilder WithTcpServer(Action<MqttClientTcpOptions> optionsBuilder)
|
||||
{
|
||||
if (optionsBuilder == null)
|
||||
@@ -373,6 +385,18 @@ namespace MQTTnet.Client
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillContentType(string willContentType)
|
||||
{
|
||||
_options.WillContentType = willContentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillCorrelationData(byte[] willCorrelationData)
|
||||
{
|
||||
_options.WillCorrelationData = willCorrelationData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillDelayInterval(uint willDelayInterval)
|
||||
{
|
||||
_options.WillDelayInterval = willDelayInterval;
|
||||
@@ -384,27 +408,33 @@ namespace MQTTnet.Client
|
||||
_options.WillPayload = willPayload;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public MqttClientOptionsBuilder WithWillPayload(string willPayload)
|
||||
{
|
||||
if (string.IsNullOrEmpty(willPayload))
|
||||
{
|
||||
return WithWillPayload((byte[])null);
|
||||
}
|
||||
|
||||
|
||||
_options.WillPayload = Encoding.UTF8.GetBytes(willPayload);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillPayloadFormatIndicator(MqttPayloadFormatIndicator willPayloadFormatIndicator)
|
||||
{
|
||||
_options.WillPayloadFormatIndicator = willPayloadFormatIndicator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel willQualityOfServiceLevel)
|
||||
{
|
||||
_options.WillQualityOfServiceLevel = willQualityOfServiceLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillTopic(string willTopic)
|
||||
public MqttClientOptionsBuilder WithWillResponseTopic(string willResponseTopic)
|
||||
{
|
||||
_options.WillTopic = willTopic;
|
||||
_options.WillResponseTopic = willResponseTopic;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -413,38 +443,20 @@ namespace MQTTnet.Client
|
||||
_options.WillRetain = willRetain;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillContentType(string willContentType)
|
||||
|
||||
public MqttClientOptionsBuilder WithWillTopic(string willTopic)
|
||||
{
|
||||
_options.WillContentType = willContentType;
|
||||
_options.WillTopic = willTopic;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillCorrelationData(byte[] willCorrelationData)
|
||||
{
|
||||
_options.WillCorrelationData = willCorrelationData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillResponseTopic(string willResponseTopic)
|
||||
{
|
||||
_options.WillResponseTopic = willResponseTopic;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithWillPayloadFormatIndicator(MqttPayloadFormatIndicator willPayloadFormatIndicator)
|
||||
{
|
||||
_options.WillPayloadFormatIndicator = willPayloadFormatIndicator;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public MqttClientOptionsBuilder WithWillUserProperty(string name, string value)
|
||||
{
|
||||
if (_options.WillUserProperties == null)
|
||||
{
|
||||
_options.WillUserProperties = new List<MqttUserProperty>();
|
||||
}
|
||||
|
||||
|
||||
_options.WillUserProperties.Add(new MqttUserProperty(name, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,12 @@ namespace MQTTnet.Implementations
|
||||
|
||||
var bufferWriter = new MqttBufferWriter(options.WriterBufferSize, options.WriterBufferSizeMax);
|
||||
var packetFormatterAdapter = new MqttPacketFormatterAdapter(options.ProtocolVersion, bufferWriter);
|
||||
return new MqttChannelAdapter(channel, packetFormatterAdapter, packetInspector, logger);
|
||||
|
||||
return new MqttChannelAdapter(channel, packetFormatterAdapter, logger)
|
||||
{
|
||||
AllowPacketFragmentation = options.AllowPacketFragmentation,
|
||||
PacketInspector = packetInspector
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace MQTTnet.Implementations
|
||||
var packetFormatterAdapter = new MqttPacketFormatterAdapter(bufferWriter);
|
||||
var tcpChannel = new MqttTcpChannel(args.Socket, clientCertificate, _options);
|
||||
|
||||
using (var clientAdapter = new MqttChannelAdapter(tcpChannel, packetFormatterAdapter, null, _rootLogger))
|
||||
using (var clientAdapter = new MqttChannelAdapter(tcpChannel, packetFormatterAdapter, _rootLogger))
|
||||
{
|
||||
await clientHandler(clientAdapter).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace MQTTnet.Implementations
|
||||
var bufferWriter = new MqttBufferWriter(_serverOptions.WriterBufferSize, _serverOptions.WriterBufferSizeMax);
|
||||
var packetFormatterAdapter = new MqttPacketFormatterAdapter(bufferWriter);
|
||||
|
||||
using (var clientAdapter = new MqttChannelAdapter(tcpChannel, packetFormatterAdapter, null, _rootLogger))
|
||||
using (var clientAdapter = new MqttChannelAdapter(tcpChannel, packetFormatterAdapter, _rootLogger))
|
||||
{
|
||||
await clientHandler(clientAdapter).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user