@@ -13,13 +13,15 @@ namespace MQTTnet.Implementations | |||||
{ | { | ||||
public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable | public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable | ||||
{ | { | ||||
private Stream _receiveStream; | |||||
private Stream _rawStream; | |||||
private Stream _sendStream; | private Stream _sendStream; | ||||
private Stream _receiveStream; | |||||
private Socket _socket; | private Socket _socket; | ||||
private SslStream _sslStream; | private SslStream _sslStream; | ||||
public Stream ReceiveStream => _receiveStream; | |||||
public Stream RawStream => _rawStream; | |||||
public Stream SendStream => _sendStream; | public Stream SendStream => _sendStream; | ||||
public Stream ReceiveStream => _receiveStream; | |||||
/// <summary> | /// <summary> | ||||
/// called on client sockets are created in connect | /// called on client sockets are created in connect | ||||
@@ -92,8 +94,9 @@ namespace MQTTnet.Implementations | |||||
private void CreateCommStreams( Socket socket, SslStream sslStream ) | private void CreateCommStreams( Socket socket, SslStream sslStream ) | ||||
{ | { | ||||
//cannot use this as default buffering prevents from receiving the first connect message | //cannot use this as default buffering prevents from receiving the first connect message | ||||
_receiveStream = (Stream)sslStream ?? new NetworkStream( socket ); | |||||
_sendStream = new BufferedStream( _receiveStream, BufferConstants.Size ); | |||||
_rawStream = (Stream)sslStream ?? new NetworkStream( socket ); | |||||
_sendStream = new BufferedStream( _rawStream, BufferConstants.Size ); | |||||
_receiveStream = new BufferedStream( _rawStream, BufferConstants.Size ); | |||||
} | } | ||||
private static X509CertificateCollection LoadCertificates(MqttClientOptions options) | private static X509CertificateCollection LoadCertificates(MqttClientOptions options) | ||||
@@ -12,10 +12,11 @@ namespace MQTTnet.Implementations | |||||
public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable | public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable | ||||
{ | { | ||||
private ClientWebSocket _webSocket = new ClientWebSocket(); | private ClientWebSocket _webSocket = new ClientWebSocket(); | ||||
public Stream ReceiveStream { get; private set; } | |||||
public Stream SendStream { get; private set; } | |||||
public Stream RawStream { get; private set; } | |||||
public Stream SendStream => RawStream; | |||||
public Stream ReceiveStream => RawStream; | |||||
public async Task ConnectAsync(MqttClientOptions options) | public async Task ConnectAsync(MqttClientOptions options) | ||||
{ | { | ||||
@@ -26,7 +27,7 @@ namespace MQTTnet.Implementations | |||||
_webSocket = new ClientWebSocket(); | _webSocket = new ClientWebSocket(); | ||||
await _webSocket.ConnectAsync(new Uri(options.Server), CancellationToken.None); | await _webSocket.ConnectAsync(new Uri(options.Server), CancellationToken.None); | ||||
ReceiveStream = SendStream = new WebSocketStream(_webSocket); | |||||
RawStream = new WebSocketStream(_webSocket); | |||||
} | } | ||||
catch (WebSocketException exception) | catch (WebSocketException exception) | ||||
{ | { | ||||
@@ -36,7 +37,7 @@ namespace MQTTnet.Implementations | |||||
public Task DisconnectAsync() | public Task DisconnectAsync() | ||||
{ | { | ||||
ReceiveStream = null; | |||||
RawStream = null; | |||||
return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); | return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); | ||||
} | } | ||||
@@ -19,6 +19,7 @@ namespace MQTTnet.Implementations | |||||
public Stream ReceiveStream => _dataStream; | public Stream ReceiveStream => _dataStream; | ||||
public Stream RawStream => _dataStream; | |||||
public Stream SendStream => _dataStream; | public Stream SendStream => _dataStream; | ||||
/// <summary> | /// <summary> | ||||
@@ -12,9 +12,10 @@ namespace MQTTnet.Implementations | |||||
public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable | public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable | ||||
{ | { | ||||
private ClientWebSocket _webSocket = new ClientWebSocket(); | private ClientWebSocket _webSocket = new ClientWebSocket(); | ||||
public Stream SendStream { get; private set; } | |||||
public Stream ReceiveStream { get; private set; } | |||||
public Stream SendStream => RawStream; | |||||
public Stream ReceiveStream => RawStream; | |||||
public Stream RawStream { get; private set; } | |||||
public async Task ConnectAsync(MqttClientOptions options) | public async Task ConnectAsync(MqttClientOptions options) | ||||
{ | { | ||||
@@ -25,7 +26,7 @@ namespace MQTTnet.Implementations | |||||
_webSocket = new ClientWebSocket(); | _webSocket = new ClientWebSocket(); | ||||
await _webSocket.ConnectAsync(new Uri(options.Server), CancellationToken.None); | await _webSocket.ConnectAsync(new Uri(options.Server), CancellationToken.None); | ||||
SendStream = ReceiveStream = new WebSocketStream(_webSocket); | |||||
RawStream = new WebSocketStream(_webSocket); | |||||
} | } | ||||
catch (WebSocketException exception) | catch (WebSocketException exception) | ||||
{ | { | ||||
@@ -35,7 +36,7 @@ namespace MQTTnet.Implementations | |||||
public Task DisconnectAsync() | public Task DisconnectAsync() | ||||
{ | { | ||||
SendStream = ReceiveStream = null; | |||||
RawStream = null; | |||||
return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); | return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); | ||||
} | } | ||||
@@ -50,7 +50,7 @@ namespace MQTTnet.Core.Adapter | |||||
} | } | ||||
} | } | ||||
await _sendTask.ConfigureAwait( false ); | |||||
await _sendTask; // configure await false geneates stackoverflow | |||||
await _channel.SendStream.FlushAsync().TimeoutAfter( timeout ).ConfigureAwait( false ); | await _channel.SendStream.FlushAsync().TimeoutAfter( timeout ).ConfigureAwait( false ); | ||||
} | } | ||||
@@ -61,11 +61,11 @@ namespace MQTTnet.Core.Adapter | |||||
Tuple<MqttPacketHeader, MemoryStream> tuple; | Tuple<MqttPacketHeader, MemoryStream> tuple; | ||||
if (timeout > TimeSpan.Zero) | if (timeout > TimeSpan.Zero) | ||||
{ | { | ||||
tuple = await ReceiveAsync().TimeoutAfter(timeout).ConfigureAwait(false); | |||||
tuple = await ReceiveAsync(_channel.RawStream).TimeoutAfter(timeout).ConfigureAwait(false); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
tuple = await ReceiveAsync().ConfigureAwait(false); | |||||
tuple = await ReceiveAsync(_channel.RawStream).ConfigureAwait(false); | |||||
} | } | ||||
var packet = PacketSerializer.Deserialize(tuple.Item1, tuple.Item2); | var packet = PacketSerializer.Deserialize(tuple.Item1, tuple.Item2); | ||||
@@ -79,9 +79,8 @@ namespace MQTTnet.Core.Adapter | |||||
return packet; | return packet; | ||||
} | } | ||||
private async Task<Tuple<MqttPacketHeader, MemoryStream>> ReceiveAsync() | |||||
private async Task<Tuple<MqttPacketHeader, MemoryStream>> ReceiveAsync(Stream stream) | |||||
{ | { | ||||
var stream = _channel.ReceiveStream; | |||||
var header = MqttPacketReader.ReadHeaderFromSource(stream); | var header = MqttPacketReader.ReadHeaderFromSource(stream); | ||||
MemoryStream body = null; | MemoryStream body = null; | ||||
@@ -13,5 +13,7 @@ namespace MQTTnet.Core.Channel | |||||
Stream SendStream { get; } | Stream SendStream { get; } | ||||
Stream ReceiveStream { get; } | Stream ReceiveStream { get; } | ||||
Stream RawStream { get; } | |||||
} | } | ||||
} | } |
@@ -393,6 +393,8 @@ namespace MQTTnet.Core.Tests | |||||
public Stream ReceiveStream => _stream; | public Stream ReceiveStream => _stream; | ||||
public Stream RawStream => _stream; | |||||
public Stream SendStream => _stream; | public Stream SendStream => _stream; | ||||
public bool IsConnected { get; } = true; | public bool IsConnected { get; } = true; | ||||
@@ -1,6 +1,7 @@ | |||||
using System; | using System; | ||||
using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Threading; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
@@ -46,6 +47,11 @@ namespace MQTTnet.Core.Tests | |||||
return Task.Run(() => _incomingPackets.Take()); | return Task.Run(() => _incomingPackets.Take()); | ||||
} | } | ||||
public IEnumerable<MqttBasePacket> ReceivePackets( CancellationToken cancellationToken ) | |||||
{ | |||||
return _incomingPackets.GetConsumingEnumerable(); | |||||
} | |||||
private void SendPacketInternal(MqttBasePacket packet) | private void SendPacketInternal(MqttBasePacket packet) | ||||
{ | { | ||||
if (packet == null) throw new ArgumentNullException(nameof(packet)); | if (packet == null) throw new ArgumentNullException(nameof(packet)); | ||||
@@ -17,7 +17,7 @@ namespace MQTTnet.TestApp.NetFramework | |||||
public static async Task RunAsync() | public static async Task RunAsync() | ||||
{ | { | ||||
var server = Task.Run(() => RunServerAsync()); | var server = Task.Run(() => RunServerAsync()); | ||||
var client = Task.Run(() => RunClientAsync(500, TimeSpan.FromMilliseconds(10))); | |||||
var client = Task.Run(() => RunClientAsync(300, TimeSpan.FromMilliseconds(10))); | |||||
await Task.WhenAll(server, client).ConfigureAwait(false); | await Task.WhenAll(server, client).ConfigureAwait(false); | ||||
} | } | ||||