簡體   English   中英

Observable.Using {WebSocket.ReceiveAsync(); 早點中止並取消

[英]Observable.Using { WebSocket.ReceiveAsync(); } aborts and cancels early

在下面的代碼中, Connect()似乎工作正常。 然而webSocket.ReceiveAsync()ReceiveMessage()似乎設置cancelToken.IsCancellationRequested = truewebSocket.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM