mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
1883 in a weak network environment the mqtt broker is unable to detect disconnections (#1891)
* Add new setting * Align keep alive handling with RFC Only completely sent packets are treated as keep alive * Update ReleaseNotes.md
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
* [Server] Added new events for delivered and dropped messages (#1866, thanks to @kallayj).
|
* [Server] Added new events for delivered and dropped messages (#1866, thanks to @kallayj).
|
||||||
|
* [Server] The server will no longer treat a client which is receiving a large payload as alive. The packet must be received completely within the keep alive boundaries (BREAKING CHANGE!, #1883).
|
||||||
|
|||||||
@@ -83,8 +83,6 @@ namespace MQTTnet.AspNetCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsReadingPacket { get; private set; }
|
|
||||||
|
|
||||||
public bool IsSecureConnection
|
public bool IsSecureConnection
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -164,11 +162,6 @@ namespace MQTTnet.AspNetCore
|
|||||||
BytesReceived += received;
|
BytesReceived += received;
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// we did receive something but the message is not yet complete
|
|
||||||
IsReadingPacket = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (readResult.IsCompleted)
|
else if (readResult.IsCompleted)
|
||||||
{
|
{
|
||||||
@@ -189,12 +182,9 @@ namespace MQTTnet.AspNetCore
|
|||||||
// completing the channel makes sure that there is no more data read after a protocol error
|
// completing the channel makes sure that there is no more data read after a protocol error
|
||||||
_input?.Complete(exception);
|
_input?.Complete(exception);
|
||||||
_output?.Complete(exception);
|
_output?.Complete(exception);
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
IsReadingPacket = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ namespace MQTTnet.Adapter
|
|||||||
|
|
||||||
long BytesReceived { get; }
|
long BytesReceived { get; }
|
||||||
|
|
||||||
bool IsReadingPacket { get; }
|
|
||||||
|
|
||||||
Task ConnectAsync(CancellationToken cancellationToken);
|
Task ConnectAsync(CancellationToken cancellationToken);
|
||||||
|
|
||||||
Task DisconnectAsync(CancellationToken cancellationToken);
|
Task DisconnectAsync(CancellationToken cancellationToken);
|
||||||
|
|||||||
@@ -55,8 +55,6 @@ namespace MQTTnet.Adapter
|
|||||||
|
|
||||||
public string Endpoint => _channel.Endpoint;
|
public string Endpoint => _channel.Endpoint;
|
||||||
|
|
||||||
public bool IsReadingPacket { get; private set; }
|
|
||||||
|
|
||||||
public bool IsSecureConnection => _channel.IsSecureConnection;
|
public bool IsSecureConnection => _channel.IsSecureConnection;
|
||||||
|
|
||||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||||
@@ -389,53 +387,45 @@ namespace MQTTnet.Adapter
|
|||||||
return ReceivedMqttPacket.Empty;
|
return ReceivedMqttPacket.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsReadingPacket = true;
|
var fixedHeader = readFixedHeaderResult.FixedHeader;
|
||||||
try
|
if (fixedHeader.RemainingLength == 0)
|
||||||
{
|
{
|
||||||
var fixedHeader = readFixedHeaderResult.FixedHeader;
|
return new ReceivedMqttPacket(fixedHeader.Flags, EmptyBuffer.ArraySegment, 2);
|
||||||
if (fixedHeader.RemainingLength == 0)
|
}
|
||||||
|
|
||||||
|
var bodyLength = fixedHeader.RemainingLength;
|
||||||
|
var body = new byte[bodyLength];
|
||||||
|
|
||||||
|
var bodyOffset = 0;
|
||||||
|
var chunkSize = Math.Min(ReadBufferSize, bodyLength);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var bytesLeft = body.Length - bodyOffset;
|
||||||
|
if (chunkSize > bytesLeft)
|
||||||
{
|
{
|
||||||
return new ReceivedMqttPacket(fixedHeader.Flags, EmptyBuffer.ArraySegment, 2);
|
chunkSize = bytesLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyLength = fixedHeader.RemainingLength;
|
var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false);
|
||||||
var body = new byte[bodyLength];
|
|
||||||
|
|
||||||
var bodyOffset = 0;
|
if (cancellationToken.IsCancellationRequested)
|
||||||
var chunkSize = Math.Min(ReadBufferSize, bodyLength);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
var bytesLeft = body.Length - bodyOffset;
|
return ReceivedMqttPacket.Empty;
|
||||||
if (chunkSize > bytesLeft)
|
}
|
||||||
{
|
|
||||||
chunkSize = bytesLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false);
|
if (readBytes == 0)
|
||||||
|
{
|
||||||
|
return ReceivedMqttPacket.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
bodyOffset += readBytes;
|
||||||
{
|
} while (bodyOffset < bodyLength);
|
||||||
return ReceivedMqttPacket.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readBytes == 0)
|
PacketInspector?.FillReceiveBuffer(body);
|
||||||
{
|
|
||||||
return ReceivedMqttPacket.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyOffset += readBytes;
|
var bodySegment = new ArraySegment<byte>(body, 0, bodyLength);
|
||||||
} while (bodyOffset < bodyLength);
|
return new ReceivedMqttPacket(fixedHeader.Flags, bodySegment, fixedHeader.TotalLength);
|
||||||
|
|
||||||
PacketInspector?.FillReceiveBuffer(body);
|
|
||||||
|
|
||||||
var bodySegment = new ArraySegment<byte>(body, 0, bodyLength);
|
|
||||||
return new ReceivedMqttPacket(fixedHeader.Flags, bodySegment, fixedHeader.TotalLength);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
IsReadingPacket = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WrapAndThrowException(Exception exception)
|
static bool WrapAndThrowException(Exception exception)
|
||||||
|
|||||||
@@ -107,13 +107,6 @@ namespace MQTTnet.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection.ChannelAdapter.IsReadingPacket)
|
|
||||||
{
|
|
||||||
// The connection is currently reading a (large) packet. So it is obviously
|
|
||||||
// doing something and thus "connected".
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values described here: [MQTT-3.1.2-24].
|
// Values described here: [MQTT-3.1.2-24].
|
||||||
// If the client sends 5 sec. the server will allow up to 7.5 seconds.
|
// If the client sends 5 sec. the server will allow up to 7.5 seconds.
|
||||||
// If the client sends 1 sec. the server will allow up to 1.5 seconds.
|
// If the client sends 1 sec. the server will allow up to 1.5 seconds.
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MQTTnet.Server
|
||||||
|
{
|
||||||
|
public sealed class MqttServerKeepAliveOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// When this mode is enabled the MQTT server will not close a connection when the
|
||||||
|
/// client is currently sending a (large) payload. This may lead to "dead" connections
|
||||||
|
/// When this mode is disabled the MQTT server will disconnect a client when the keep
|
||||||
|
/// alive timeout is reached even if the client is currently sending a (large) payload.
|
||||||
|
/// </summary>
|
||||||
|
public bool DisconnectClientWhenReadingPayload { get; set; }
|
||||||
|
|
||||||
|
public TimeSpan MonitorInterval { get; set; } = TimeSpan.FromMilliseconds(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,19 @@ namespace MQTTnet.Server
|
|||||||
public sealed class MqttServerOptions
|
public sealed class MqttServerOptions
|
||||||
{
|
{
|
||||||
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(100);
|
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(100);
|
||||||
|
|
||||||
public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions();
|
public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions();
|
||||||
|
|
||||||
public bool EnablePersistentSessions { get; set; }
|
public bool EnablePersistentSessions { get; set; }
|
||||||
|
|
||||||
public TimeSpan KeepAliveMonitorInterval { get; set; } = TimeSpan.FromMilliseconds(500);
|
[Obsolete("Use KeepAliveOptions instead.")]
|
||||||
|
public TimeSpan KeepAliveMonitorInterval
|
||||||
|
{
|
||||||
|
get => KeepAliveOptions.MonitorInterval;
|
||||||
|
set => KeepAliveOptions.MonitorInterval = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttServerKeepAliveOptions KeepAliveOptions { get; } = new MqttServerKeepAliveOptions();
|
||||||
|
|
||||||
public int MaxPendingMessagesPerClient { get; set; } = 250;
|
public int MaxPendingMessagesPerClient { get; set; } = 250;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user