1

我正在使用System.Threading.Channel.NET 客户端进行 SignalR 服务器到客户端的流式传输。用法相当基本,类似于介绍性文档中描述的内容。

集线器代码与此类似:

public ChannelReader<byte[]> Retrieve(Guid id, CancellationToken cancellationToken)
{
    var channel = Channel.CreateBounded<byte[]>(_limit);
    _ = WriteItemsAsync(channel.Writer, id, cancellationToken);
    return channel.Reader;
}

private async Task WriteItemsAsync(ChannelWriter<byte[]> writer, Guid id, CancellationToken cancellationToken)
{
    Exception localException = null;
    try
    {
        //loop and write to the ChannelWriter until finished
    }
    catch (Exception ex)
    {
        localException = ex;
    }
    finally
    {
        writer.Complete(localException);
    }
}

和客户端类似:

var channel = await hubConnection.StreamAsChannelAsync<byte[]>("Retrieve", _guid, cancellationTokenSource.Token);

while (await channel.WaitToReadAsync())
{
    while (channel.TryRead(out var data))
    {
        //handle data
    }
}

当我的集线器方法完成流式传输时,它会调用Complete()它的ChannelWriter. SignalR 大概是在内部看到Complete对相应 的调用ChannelReader,将其转换为内部 SignalR 消息并将其传递给客户端。然后,SignalR将客户端自己ChannelReader的代码标记为完成,我的客户端代码将自己的工作封装在流上。

从服务器到客户端的“已完成”通知是否可以保证交付?在集线器向客户端广播非流式消息的其他情况下,它通常“触发并忘记”,但我必须假设调用Complete流式传输Channel已确认传递,否则客户端可能处于它的状态ChannelReader当服务器将流视为关闭时,无限期地保持流打开。

这个问题不太重要,但我问的原因是我试图缩小这种情况,即消耗 SignalR 流接口的数据流管道偶尔会挂起,而且似乎唯一挂起的地方是SignalR 客户端的某处。

4

1 回答 1

1

我在 github 上询问了开发人员:https ://github.com/dotnet/aspnetcore/issues/30128 。

这是一个快速的总结:

“SignalR 上的消息与 TCP 一样可靠。基本上,这意味着要么您收到消息,要么连接关闭。在这两种情况下,客户端的通道都将完成。”

和:

“是的,它不应该永远挂起。它要么发送完整的消息,要么断开连接。无论哪种方式,挂起都是客户端的错误”

于 2021-02-12T02:39:38.787 回答