mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-16 17:23:04 +08:00
When a publish, subscribe or unsubscribe request was cancelled or timed out client-side, the corresponding awaitable was removed from the packet dispatcher. A subsequent PUBACK / PUBCOMP / SUBACK / UNSUBACK arriving from the broker then fell through to the default case and raised an MqttProtocolViolationException, which forced a disconnect. Under high publish load (issue #2079) and from multiple threads (issue #2078) this manifested as sporadic connection drops. Match these acknowledgement packets explicitly and log a warning when no awaiter is registered, instead of treating it as a protocol violation. The connection is now preserved. Also documents the thread-safety guarantees of IMqttClient: publish, subscribe, unsubscribe and ping operations are safe to invoke concurrently. Connect / disconnect must still be coordinated. Co-authored-by: meisa <meisa@MAFDEL> Co-authored-by: christian <6939810+chkr1011@users.noreply.github.com>
49 lines
2.2 KiB
C#
49 lines
2.2 KiB
C#
using MQTTnet.Diagnostics.PacketInspection;
|
|
|
|
namespace MQTTnet;
|
|
|
|
/// <summary>
|
|
/// Represents an MQTT client.
|
|
/// <para>
|
|
/// Instances of <see cref="IMqttClient" /> are safe for concurrent use: <see cref="PublishAsync" />,
|
|
/// <see cref="SubscribeAsync" />, <see cref="UnsubscribeAsync" /> and <see cref="PingAsync" /> may be
|
|
/// invoked from multiple threads at the same time. Outgoing packets are serialized internally so
|
|
/// that they reach the network in well-formed order, and incoming acknowledgements are routed back
|
|
/// to the corresponding caller via the packet identifier.
|
|
/// </para>
|
|
/// <para>
|
|
/// <see cref="ConnectAsync" /> and <see cref="DisconnectAsync" /> must not be called concurrently
|
|
/// with each other or with publish/subscribe operations. Coordinate connection lifecycle changes on
|
|
/// a single thread.
|
|
/// </para>
|
|
/// </summary>
|
|
public interface IMqttClient : IDisposable
|
|
{
|
|
event Func<MqttApplicationMessageReceivedEventArgs, Task> ApplicationMessageReceivedAsync;
|
|
|
|
event Func<MqttClientConnectedEventArgs, Task> ConnectedAsync;
|
|
|
|
event Func<MqttClientConnectingEventArgs, Task> ConnectingAsync;
|
|
|
|
event Func<MqttClientDisconnectedEventArgs, Task> DisconnectedAsync;
|
|
|
|
event Func<InspectMqttPacketEventArgs, Task> InspectPacketAsync;
|
|
|
|
bool IsConnected { get; }
|
|
|
|
MqttClientOptions Options { get; }
|
|
|
|
Task<MqttClientConnectResult> ConnectAsync(MqttClientOptions options, CancellationToken cancellationToken = default);
|
|
|
|
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken = default);
|
|
|
|
Task PingAsync(CancellationToken cancellationToken = default);
|
|
|
|
Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken = default);
|
|
|
|
Task SendEnhancedAuthenticationExchangeDataAsync(MqttEnhancedAuthenticationExchangeData data, CancellationToken cancellationToken = default);
|
|
|
|
Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken = default);
|
|
|
|
Task<MqttClientUnsubscribeResult> UnsubscribeAsync(MqttClientUnsubscribeOptions options, CancellationToken cancellationToken = default);
|
|
} |