[英]Observable.Using { WebSocket.ReceiveAsync(); } aborts and cancels early
在下面的代碼中, Connect()
似乎工作正常。 然而webSocket.ReceiveAsync()
在ReceiveMessage()
似乎設置cancelToken.IsCancellationRequested = true
和webSocket.State = Aborted
的那一刻服務器不會有什么提供。 同時,相同的ReceiveAsync()
調用引發(無用的) OperationCanceledException
,沒有內部異常。
我使用我認為相同的WebSocket交互使用相同的服務器沒有這個問題,但使用更簡單的異步代碼。 直到我嘗試將它轉換成一個可觀察到我有這個問題。
是否被Rx取消,還是取消了? 我發現在.NET WebSockets中由於未被觀察到的例外而引起了這樣的事情( http://www.salmanq.com/blog/5-things-you-probably-didnt-know-about-net-websockets/2013/ 04 / ),但在添加TaskScheduler.UnobservedTaskException += ExceptionLogger
之后,我找不到任何證據。
有任何想法嗎?
public static IObservable<string> GetWebSocketStream(Uri uri)
{
var buffer = new byte[2048];
return Observable
.Using(cancelToken => Connect(uri, cancelToken),
(webSocket, cancelToken) => Task.FromResult(
Observable.Defer(
() => ReceiveMessage(webSocket, buffer, cancelToken).ToObservable()
).Repeat()
)
).Publish().RefCount();
}
private static async Task<ClientWebSocket> Connect(Uri uri, CancellationToken token)
{
var webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(uri, token).ConfigureAwait(false);
return webSocket;
}
private static async Task<string> ReceiveMessage(ClientWebSocket webSocket, byte[] buffer, CancellationToken cancelToken)
{
var segment = new ArraySegment<byte>(buffer);
var message = new StringBuilder();
WebSocketReceiveResult result;
do
{
result = await webSocket.ReceiveAsync(segment, cancelToken).ConfigureAwait(false);
message.Append(Encoding.UTF8.GetString(segment.Array, 0, result.Count));
} while (!cancelToken.IsCancellationRequested && !result.EndOfMessage);
return message.ToString();
}
編輯:澄清一下,我的問題/問題可能與BOTH WebSockets和Rx有關。 以下類似的代碼在同一設備上保持打開狀態並接收數據:
public static void Test() {
var ts = new CancellationTokenSource();
AsyncTest(new Uri("ws://server/test/"), ts.Token).Wait();
}
public static async Task AsyncTest(Uri uri, CancellationToken token) {
var socket = await GetConnectedWebSocket(uri, token);
var buffer = new byte[4000];
while (!token.IsCancellationRequested)
{
try
{
var msg = await ReceiveMessage(socket, buffer, token);
Debug.WriteLine(msg);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
}
問題是將cancelToken
傳遞給ReceiveMessage
函數。 在Task
完成之前的Rx實現中(在您的情況下為Task.FromResult
)執行清理代碼,如果處理了cancelToken
則作為端口。 當我嘗試使用這樣的代碼時遇到了同樣的問題:
return Observable.Using(cancelToken => Connect(uri, authToken, cancelToken), (webSocket, token) =>
Task.FromResult(Observable.Create<string>((observer) => WebSocketReceiver.WebSocketReceiverSubscribe(observer, webSocket, cancelToken))))
.Publish().RefCount();
但是這段代碼有效:
return Observable.Using(cancelToken => Connect(uri, authToken, cancelToken), (webSocket, token) =>
Task.FromResult(Observable.Create<string>((observer, ct) => WebSocketReceiver.WebSocketReceiverSubscribe(observer, webSocket, ct))))
.Publish().RefCount();
正如我所看到的, Observable.Defer
不傳遞CancellationToken
對象,因此您必須創建外部對象並將其傳遞給ReceiveMessage
。 或者你也可以像我的例子一樣使用Observable.Create
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.