mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-16 01:03:01 +08:00
Fixed WebSocket client stream
This commit is contained in:
@@ -10,9 +10,11 @@
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</description>
|
||||
<releaseNotes>* [Core] Fixed library reference issues for .NET 4.6 (Thanks to @JanEggers).
|
||||
<releaseNotes>* [Core] Fixed library reference issues for .NET 4.6 and netstandard 2.0 (Thanks to @JanEggers).
|
||||
* [Core] Several COM exceptions are now wrapped properly resulting in less warnings in the trace.
|
||||
* [Core] Removed application message payload from trace to reduce trace size and increase performance.
|
||||
* [Client] Fixed WebSocket sub protocol negotiation for ASP.NET Core 2 servers (Thanks to @JanEggers).
|
||||
* [Client] Fixed broken connection after 30 seconds then using WebSocket protocol (Thanks to @ChristianRiedl).
|
||||
* [Server] Client connections are now closed when the server is stopped (Thanks to @zhudanfei).
|
||||
* [Server] Published messages from the server are now retained (if set) (Thanks to @ChristianRiedl). BREAKING CHANGE!
|
||||
</releaseNotes>
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Core.Adapter;
|
||||
using MQTTnet.Core.Channel;
|
||||
using MQTTnet.Core.Server;
|
||||
using MQTTnet.Implementations;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
@@ -47,47 +43,5 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
StopAsync();
|
||||
}
|
||||
|
||||
private class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable
|
||||
{
|
||||
private readonly WebSocket _webSocket;
|
||||
|
||||
public MqttWebSocketServerChannel(WebSocket webSocket)
|
||||
{
|
||||
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
|
||||
|
||||
RawReceiveStream = new WebSocketStream(_webSocket);
|
||||
}
|
||||
|
||||
public Stream SendStream => RawReceiveStream;
|
||||
public Stream ReceiveStream => RawReceiveStream;
|
||||
public Stream RawReceiveStream { get; }
|
||||
|
||||
public Task ConnectAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task DisconnectAsync()
|
||||
{
|
||||
RawReceiveStream?.Dispose();
|
||||
|
||||
if (_webSocket == null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RawReceiveStream?.Dispose();
|
||||
SendStream?.Dispose();
|
||||
ReceiveStream?.Dispose();
|
||||
|
||||
_webSocket?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Core.Channel;
|
||||
using MQTTnet.Implementations;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable
|
||||
{
|
||||
private WebSocket _webSocket;
|
||||
|
||||
public MqttWebSocketServerChannel(WebSocket webSocket)
|
||||
{
|
||||
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
|
||||
|
||||
SendStream = new WebSocketStream(_webSocket);
|
||||
ReceiveStream = SendStream;
|
||||
}
|
||||
|
||||
public Stream SendStream { get; private set; }
|
||||
public Stream ReceiveStream { get; private set; }
|
||||
|
||||
public Task ConnectAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task DisconnectAsync()
|
||||
{
|
||||
if (_webSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SendStream?.Dispose();
|
||||
ReceiveStream?.Dispose();
|
||||
|
||||
_webSocket?.Dispose();
|
||||
|
||||
SendStream = null;
|
||||
ReceiveStream = null;
|
||||
_webSocket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,10 @@ namespace MQTTnet.Implementations
|
||||
{
|
||||
public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable
|
||||
{
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
|
||||
public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user.
|
||||
|
||||
private readonly MqttClientWebSocketOptions _options;
|
||||
private ClientWebSocket _webSocket;
|
||||
|
||||
@@ -80,7 +84,7 @@ namespace MQTTnet.Implementations
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_webSocket = null;
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -10,7 +12,9 @@ namespace MQTTnet.Implementations
|
||||
public class WebSocketStream : Stream
|
||||
{
|
||||
private readonly WebSocket _webSocket;
|
||||
|
||||
private readonly byte[] _chunkBuffer = new byte[MqttWebSocketChannel.BufferSize];
|
||||
private readonly Queue<byte> _buffer = new Queue<byte>(MqttWebSocketChannel.BufferSize);
|
||||
|
||||
public WebSocketStream(WebSocket webSocket)
|
||||
{
|
||||
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
|
||||
@@ -34,33 +38,9 @@ namespace MQTTnet.Implementations
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
public override Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var currentOffset = offset;
|
||||
var targetOffset = offset + count;
|
||||
while (_webSocket.State == WebSocketState.Open && currentOffset < targetOffset)
|
||||
{
|
||||
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, currentOffset, count), cancellationToken).ConfigureAwait(false);
|
||||
currentOffset += response.Count;
|
||||
count -= response.Count;
|
||||
|
||||
if (response.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (_webSocket.State == WebSocketState.Closed)
|
||||
{
|
||||
throw new MqttCommunicationException( "connection closed" );
|
||||
}
|
||||
|
||||
return currentOffset - offset;
|
||||
}
|
||||
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
@@ -68,11 +48,58 @@ namespace MQTTnet.Implementations
|
||||
return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
var bytesRead = 0;
|
||||
|
||||
// Use existing date from buffer.
|
||||
while (count > 0 && _buffer.Any())
|
||||
{
|
||||
buffer[offset++] = _buffer.Dequeue();
|
||||
count--;
|
||||
bytesRead++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
while (_webSocket.State == WebSocketState.Open)
|
||||
{
|
||||
await FetchChunkAsync(cancellationToken);
|
||||
|
||||
while (count > 0 && _buffer.Any())
|
||||
{
|
||||
buffer[offset++] = _buffer.Dequeue();
|
||||
count--;
|
||||
bytesRead++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
if (_webSocket.State == WebSocketState.Closed)
|
||||
{
|
||||
throw new MqttCommunicationException("WebSocket connection closed.");
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
@@ -82,5 +109,21 @@ namespace MQTTnet.Implementations
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private async Task FetchChunkAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(_chunkBuffer, 0, _chunkBuffer.Length), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
for (var i = 0; i < response.Count; i++)
|
||||
{
|
||||
var @byte = _chunkBuffer[i];
|
||||
_buffer.Enqueue(@byte);
|
||||
}
|
||||
|
||||
if (response.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace MQTTnet
|
||||
|
||||
public MqttFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
public ILoggerFactory GetLoggerFactory()
|
||||
|
||||
@@ -60,14 +60,14 @@ namespace MQTTnet.Core.Client
|
||||
await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
|
||||
_logger.LogTrace("Connection with server established.");
|
||||
|
||||
await SetupIncomingPacketProcessingAsync().ConfigureAwait(false);
|
||||
await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false);
|
||||
|
||||
_logger.LogTrace("MQTT connection with server established.");
|
||||
|
||||
if (_options.KeepAlivePeriod != TimeSpan.Zero)
|
||||
{
|
||||
StartSendKeepAliveMessages(_cancellationTokenSource.Token);
|
||||
StartSendingKeepAliveMessages(_cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
IsConnected = true;
|
||||
@@ -96,7 +96,6 @@ namespace MQTTnet.Core.Client
|
||||
finally
|
||||
{
|
||||
await DisconnectInternalAsync().ConfigureAwait(false);
|
||||
_scopeHandle.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,36 +148,36 @@ namespace MQTTnet.Core.Client
|
||||
switch (qosGroup.Key)
|
||||
{
|
||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||
{
|
||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
{
|
||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||
{
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
|
||||
}
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||
{
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
|
||||
await SendAndReceiveAsync<MqttPubCompPacket>(pubRecPacket.CreateResponse<MqttPubRelPacket>()).ConfigureAwait(false);
|
||||
}
|
||||
foreach (var publishPacket in qosPackets)
|
||||
{
|
||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
|
||||
await SendAndReceiveAsync<MqttPubCompPacket>(pubRecPacket.CreateResponse<MqttPubRelPacket>()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +190,7 @@ namespace MQTTnet.Core.Client
|
||||
Username = _options.Credentials?.Username,
|
||||
Password = _options.Credentials?.Password,
|
||||
CleanSession = _options.CleanSession,
|
||||
KeepAlivePeriod = (ushort) _options.KeepAlivePeriod.TotalSeconds,
|
||||
KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
|
||||
WillMessage = willApplicationMessage
|
||||
};
|
||||
|
||||
@@ -204,24 +203,6 @@ namespace MQTTnet.Core.Client
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task SetupIncomingPacketProcessingAsync()
|
||||
{
|
||||
_isReceivingPackets = false;
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Factory.StartNew(
|
||||
() => ReceivePackets(_cancellationTokenSource.Token),
|
||||
_cancellationTokenSource.Token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
while (!_isReceivingPackets && _cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfNotConnected()
|
||||
{
|
||||
if (!IsConnected) throw new MqttCommunicationException("The client is not connected.");
|
||||
@@ -234,6 +215,8 @@ namespace MQTTnet.Core.Client
|
||||
|
||||
private async Task DisconnectInternalAsync()
|
||||
{
|
||||
_scopeHandle?.Dispose();
|
||||
|
||||
var clientWasConnected = IsConnected;
|
||||
IsConnected = false;
|
||||
|
||||
@@ -258,6 +241,7 @@ namespace MQTTnet.Core.Client
|
||||
}
|
||||
finally
|
||||
{
|
||||
_logger.LogInformation("Disconnected.");
|
||||
Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected));
|
||||
}
|
||||
}
|
||||
@@ -324,7 +308,7 @@ namespace MQTTnet.Core.Client
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
FireApplicationMessageReceivedEvent(publishPacket);
|
||||
await SendAsync(new MqttPubAckPacket {PacketIdentifier = publishPacket.PacketIdentifier});
|
||||
await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -337,7 +321,7 @@ namespace MQTTnet.Core.Client
|
||||
}
|
||||
|
||||
FireApplicationMessageReceivedEvent(publishPacket);
|
||||
await SendAsync(new MqttPubRecPacket {PacketIdentifier = publishPacket.PacketIdentifier});
|
||||
await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -363,12 +347,12 @@ namespace MQTTnet.Core.Client
|
||||
{
|
||||
var packetAwaiter = _packetDispatcher.WaitForPacketAsync(requestPacket, typeof(TResponsePacket), _options.CommunicationTimeout);
|
||||
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, requestPacket).ConfigureAwait(false);
|
||||
return (TResponsePacket) await packetAwaiter.ConfigureAwait(false);
|
||||
return (TResponsePacket)await packetAwaiter.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private ushort GetNewPacketIdentifier()
|
||||
{
|
||||
return (ushort) Interlocked.Increment(ref _latestPacketIdentifier);
|
||||
return (ushort)Interlocked.Increment(ref _latestPacketIdentifier);
|
||||
}
|
||||
|
||||
private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
|
||||
@@ -390,6 +374,12 @@ namespace MQTTnet.Core.Client
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await DisconnectInternalAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
@@ -412,7 +402,7 @@ namespace MQTTnet.Core.Client
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReceivePackets(CancellationToken cancellationToken)
|
||||
private async Task ReceivePacketsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Start receiving packets.");
|
||||
|
||||
@@ -423,6 +413,7 @@ namespace MQTTnet.Core.Client
|
||||
_isReceivingPackets = true;
|
||||
|
||||
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
@@ -433,6 +424,12 @@ namespace MQTTnet.Core.Client
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await DisconnectInternalAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
@@ -458,15 +455,34 @@ namespace MQTTnet.Core.Client
|
||||
private void StartProcessReceivedPacket(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(() => ProcessReceivedPacketAsync(packet), cancellationToken).ConfigureAwait(false);
|
||||
Task.Run(
|
||||
() => ProcessReceivedPacketAsync(packet),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
}
|
||||
|
||||
private void StartSendKeepAliveMessages(CancellationToken cancellationToken)
|
||||
private async Task StartReceivingPacketsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_isReceivingPackets = false;
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(
|
||||
async () => await ReceivePacketsAsync(cancellationToken),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
while (!_isReceivingPackets && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartSendingKeepAliveMessages(CancellationToken cancellationToken)
|
||||
{
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Factory.StartNew(() => SendKeepAliveMessagesAsync(cancellationToken), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)
|
||||
.ConfigureAwait(false);
|
||||
Task.Run(
|
||||
async () => await SendKeepAliveMessagesAsync(cancellationToken),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using MQTTnet.Core.Protocol;
|
||||
using MQTTnet.Core.Protocol;
|
||||
|
||||
namespace MQTTnet.Core.Packets
|
||||
{
|
||||
@@ -19,7 +18,7 @@ namespace MQTTnet.Core.Packets
|
||||
{
|
||||
return nameof(MqttPublishPacket) +
|
||||
": [Topic=" + Topic + "]" +
|
||||
" [Payload=" + Convert.ToBase64String(Payload) + "]" +
|
||||
" [PayloadLength=" + Payload?.Length + "]" +
|
||||
" [QoSLevel=" + QualityOfServiceLevel + "]" +
|
||||
" [Dup=" + Dup + "]" +
|
||||
" [Retain=" + Retain + "]" +
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace MQTTnet.Core.Serializer
|
||||
|
||||
if (buffer == -1)
|
||||
{
|
||||
break;
|
||||
throw new MqttCommunicationException("Connection closed while reading remaining length data.");
|
||||
}
|
||||
|
||||
encodedByte = (byte)buffer;
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock>Received messages:</TextBlock>
|
||||
<CheckBox x:Name="AddReceivedMessagesToList" IsChecked="True">Add received messages to list</CheckBox>
|
||||
<ListBox MinHeight="50" MaxHeight="250" x:Name="ReceivedMessages" Margin="0,0,0,10">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
|
||||
@@ -30,14 +30,14 @@ namespace MQTTnet.TestApp.UniversalWindows
|
||||
|
||||
private async void OnTraceMessagePublished(object sender, MqttNetTraceMessagePublishedEventArgs e)
|
||||
{
|
||||
await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
|
||||
var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}";
|
||||
if (e.TraceMessage.Exception != null)
|
||||
{
|
||||
text += $"{e.TraceMessage.Exception}{Environment.NewLine}";
|
||||
}
|
||||
|
||||
await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
|
||||
{
|
||||
var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}";
|
||||
if (e.TraceMessage.Exception != null)
|
||||
{
|
||||
text += $"{e.TraceMessage.Exception}{Environment.NewLine}";
|
||||
}
|
||||
|
||||
Trace.Text += text;
|
||||
});
|
||||
}
|
||||
@@ -109,11 +109,13 @@ namespace MQTTnet.TestApp.UniversalWindows
|
||||
{
|
||||
var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}";
|
||||
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
|
||||
{
|
||||
ReceivedMessages.Items.Add(item);
|
||||
if (AddReceivedMessagesToList.IsChecked == true)
|
||||
{
|
||||
ReceivedMessages.Items.Add(item);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private async void Publish(object sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user