Give Client a chance to receive Close Frame from Server (#730)
This commit is contained in:
parent
e349329dc7
commit
a4053acd06
|
|
@ -62,6 +62,9 @@ namespace Microsoft.AspNetCore.Sockets.Client.Internal
|
|||
private static readonly Action<ILogger, DateTime, string, Exception> _closingWebSocketFailed =
|
||||
LoggerMessage.Define<DateTime, string>(LogLevel.Information, 16, "{time}: Connection Id {connectionId}: Closing webSocket failed.");
|
||||
|
||||
private static readonly Action<ILogger, DateTime, string, Exception> _cancelMessage =
|
||||
LoggerMessage.Define<DateTime, string>(LogLevel.Debug, 17, "{time}: Connection Id {connectionId}: Canceled passing message to application.");
|
||||
|
||||
// Category: ServerSentEventsTransport and LongPollingTransport
|
||||
private static readonly Action<ILogger, DateTime, string, int, Uri, Exception> _sendingMessages =
|
||||
LoggerMessage.Define<DateTime, string, int, Uri>(LogLevel.Debug, 9, "{time}: Connection Id {connectionId}: Sending {count} message(s) to the server using url: {url}.");
|
||||
|
|
@ -283,6 +286,14 @@ namespace Microsoft.AspNetCore.Sockets.Client.Internal
|
|||
}
|
||||
}
|
||||
|
||||
public static void CancelMessage(this ILogger logger, string connectionId)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
_cancelMessage(logger, DateTime.Now, connectionId, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendingMessages(this ILogger logger, string connectionId, int count, Uri url)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Debug))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
private readonly ClientWebSocket _webSocket = new ClientWebSocket();
|
||||
private Channel<byte[], SendMessage> _application;
|
||||
private readonly CancellationTokenSource _transportCts = new CancellationTokenSource();
|
||||
private readonly CancellationTokenSource _receiveCts = new CancellationTokenSource();
|
||||
private readonly ILogger _logger;
|
||||
private string _connectionId;
|
||||
|
||||
|
|
@ -80,7 +81,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
|
||||
try
|
||||
{
|
||||
while (!_transportCts.Token.IsCancellationRequested)
|
||||
while (!_receiveCts.Token.IsCancellationRequested)
|
||||
{
|
||||
const int bufferSize = 4096;
|
||||
var totalBytes = 0;
|
||||
|
|
@ -91,7 +92,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
var buffer = new ArraySegment<byte>(new byte[bufferSize]);
|
||||
|
||||
//Exceptions are handled above where the send and receive tasks are being run.
|
||||
receiveResult = await _webSocket.ReceiveAsync(buffer, _transportCts.Token);
|
||||
receiveResult = await _webSocket.ReceiveAsync(buffer, _receiveCts.Token);
|
||||
if (receiveResult.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
_logger.WebSocketClosed(_connectionId, receiveResult.CloseStatus);
|
||||
|
|
@ -129,15 +130,25 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
Buffer.BlockCopy(incomingMessage[0].Array, incomingMessage[0].Offset, messageBuffer, 0, incomingMessage[0].Count);
|
||||
}
|
||||
|
||||
_logger.MessageToApp(_connectionId, messageBuffer.Length);
|
||||
while (await _application.Out.WaitToWriteAsync(_transportCts.Token))
|
||||
try
|
||||
{
|
||||
if (_application.Out.TryWrite(messageBuffer))
|
||||
if (!_transportCts.Token.IsCancellationRequested)
|
||||
{
|
||||
incomingMessage.Clear();
|
||||
break;
|
||||
_logger.MessageToApp(_connectionId, messageBuffer.Length);
|
||||
while (await _application.Out.WaitToWriteAsync(_transportCts.Token))
|
||||
{
|
||||
if (_application.Out.TryWrite(messageBuffer))
|
||||
{
|
||||
incomingMessage.Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.CancelMessage(_connectionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
|
@ -198,7 +209,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
finally
|
||||
{
|
||||
_logger.SendStopped(_connectionId);
|
||||
_transportCts.Cancel();
|
||||
TriggerCancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +259,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
await _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
|
||||
|
||||
// shutdown the transport after a timeout in case the server does not send close frame
|
||||
_transportCts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
TriggerCancel();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -258,5 +269,12 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
_logger.ClosingWebSocketFailed(_connectionId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerCancel()
|
||||
{
|
||||
// Give server 5 seconds to respond with a close frame for graceful close.
|
||||
_receiveCts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
_transportCts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection,
|
||||
TransferMode.Binary, connectionId: string.Empty);
|
||||
connectionToTransport.Out.TryComplete();
|
||||
await webSocketsTransport.Running.OrTimeout();
|
||||
await webSocketsTransport.Running.OrTimeout(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue