Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit a4053ac

Browse files
Give Client a chance to receive Close Frame from Server (#730)
1 parent e349329 commit a4053ac

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

src/Microsoft.AspNetCore.Sockets.Client.Http/Internal/SocketClientLoggerExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ internal static class SocketClientLoggerExtensions
6262
private static readonly Action<ILogger, DateTime, string, Exception> _closingWebSocketFailed =
6363
LoggerMessage.Define<DateTime, string>(LogLevel.Information, 16, "{time}: Connection Id {connectionId}: Closing webSocket failed.");
6464

65+
private static readonly Action<ILogger, DateTime, string, Exception> _cancelMessage =
66+
LoggerMessage.Define<DateTime, string>(LogLevel.Debug, 17, "{time}: Connection Id {connectionId}: Canceled passing message to application.");
67+
6568
// Category: ServerSentEventsTransport and LongPollingTransport
6669
private static readonly Action<ILogger, DateTime, string, int, Uri, Exception> _sendingMessages =
6770
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 @@ public static void ClosingWebSocketFailed(this ILogger logger, string connection
283286
}
284287
}
285288

289+
public static void CancelMessage(this ILogger logger, string connectionId)
290+
{
291+
if (logger.IsEnabled(LogLevel.Debug))
292+
{
293+
_cancelMessage(logger, DateTime.Now, connectionId, null);
294+
}
295+
}
296+
286297
public static void SendingMessages(this ILogger logger, string connectionId, int count, Uri url)
287298
{
288299
if (logger.IsEnabled(LogLevel.Debug))

src/Microsoft.AspNetCore.Sockets.Client.Http/WebSocketsTransport.cs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class WebSocketsTransport : ITransport
1919
private readonly ClientWebSocket _webSocket = new ClientWebSocket();
2020
private Channel<byte[], SendMessage> _application;
2121
private readonly CancellationTokenSource _transportCts = new CancellationTokenSource();
22+
private readonly CancellationTokenSource _receiveCts = new CancellationTokenSource();
2223
private readonly ILogger _logger;
2324
private string _connectionId;
2425

@@ -80,7 +81,7 @@ private async Task ReceiveMessages(Uri pollUrl)
8081

8182
try
8283
{
83-
while (!_transportCts.Token.IsCancellationRequested)
84+
while (!_receiveCts.Token.IsCancellationRequested)
8485
{
8586
const int bufferSize = 4096;
8687
var totalBytes = 0;
@@ -91,7 +92,7 @@ private async Task ReceiveMessages(Uri pollUrl)
9192
var buffer = new ArraySegment<byte>(new byte[bufferSize]);
9293

9394
//Exceptions are handled above where the send and receive tasks are being run.
94-
receiveResult = await _webSocket.ReceiveAsync(buffer, _transportCts.Token);
95+
receiveResult = await _webSocket.ReceiveAsync(buffer, _receiveCts.Token);
9596
if (receiveResult.MessageType == WebSocketMessageType.Close)
9697
{
9798
_logger.WebSocketClosed(_connectionId, receiveResult.CloseStatus);
@@ -129,15 +130,25 @@ private async Task ReceiveMessages(Uri pollUrl)
129130
Buffer.BlockCopy(incomingMessage[0].Array, incomingMessage[0].Offset, messageBuffer, 0, incomingMessage[0].Count);
130131
}
131132

132-
_logger.MessageToApp(_connectionId, messageBuffer.Length);
133-
while (await _application.Out.WaitToWriteAsync(_transportCts.Token))
133+
try
134134
{
135-
if (_application.Out.TryWrite(messageBuffer))
135+
if (!_transportCts.Token.IsCancellationRequested)
136136
{
137-
incomingMessage.Clear();
138-
break;
137+
_logger.MessageToApp(_connectionId, messageBuffer.Length);
138+
while (await _application.Out.WaitToWriteAsync(_transportCts.Token))
139+
{
140+
if (_application.Out.TryWrite(messageBuffer))
141+
{
142+
incomingMessage.Clear();
143+
break;
144+
}
145+
}
139146
}
140147
}
148+
catch (OperationCanceledException)
149+
{
150+
_logger.CancelMessage(_connectionId);
151+
}
141152
}
142153
}
143154
catch (OperationCanceledException)
@@ -198,7 +209,7 @@ private async Task SendMessages(Uri sendUrl)
198209
finally
199210
{
200211
_logger.SendStopped(_connectionId);
201-
_transportCts.Cancel();
212+
TriggerCancel();
202213
}
203214
}
204215

@@ -248,7 +259,7 @@ private async Task CloseWebSocket()
248259
await _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
249260

250261
// shutdown the transport after a timeout in case the server does not send close frame
251-
_transportCts.CancelAfter(TimeSpan.FromSeconds(5));
262+
TriggerCancel();
252263
}
253264
}
254265
catch (Exception ex)
@@ -258,5 +269,12 @@ private async Task CloseWebSocket()
258269
_logger.ClosingWebSocketFailed(_connectionId, ex);
259270
}
260271
}
272+
273+
private void TriggerCancel()
274+
{
275+
// Give server 5 seconds to respond with a close frame for graceful close.
276+
_receiveCts.CancelAfter(TimeSpan.FromSeconds(5));
277+
_transportCts.Cancel();
278+
}
261279
}
262280
}

test/Microsoft.AspNetCore.SignalR.Tests/WebSocketsTransportTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public async Task WebSocketsTransportStopsWhenConnectionChannelClosed()
6262
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"), channelConnection,
6363
TransferMode.Binary, connectionId: string.Empty);
6464
connectionToTransport.Out.TryComplete();
65-
await webSocketsTransport.Running.OrTimeout();
65+
await webSocketsTransport.Running.OrTimeout(TimeSpan.FromSeconds(10));
6666
}
6767
}
6868

0 commit comments

Comments
 (0)