我正在使用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 客户端的某处。