将 Channels 与 SignalR 服务器到客户端流式传输一起使用时,是否保证将服务器端 Complete 传送到客户端?
When using Channels with SignalR server-to-client streaming, is the server-side Complete guaranteed to be delivered to the client?
我正在使用 System.Threading.Channel
和 .NET 客户端进行 SignalR 服务器到客户端的流式传输。用法是相当基础的,类似于介绍 docs.
中描述的内容
集线器代码类似这样:
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
}
}
当我的集线器方法完成流式传输时,它会在其 ChannelWriter
上调用 Complete()
。据推测,SignalR 在内部看到对相应 ChannelReader
的 Complete
调用,将其转换为内部 SignalR 消息并将其传递给客户端。然后,客户端自己的 ChannelReader
被 SignalR 标记为完成,我的客户端代码在流上完成自己的工作。
从服务器到客户端的“完成”通知是否保证被传送?在集线器向客户端广播非流式消息的其他情况下,它通常“触发并忘记”,但我必须假设在流媒体 Channel
上调用 Complete
已确认交付,否则客户端可能处于持有流媒体 ChannelReader
的状态在服务器认为流已关闭时无限期打开。
这个问题不太重要,但我问的原因是我试图缩小这样一种情况,即使用 SignalR 流接口的数据流管道偶尔会挂起,这似乎是唯一的一点它挂在 SignalR 客户端的某个地方。
我在 github 上询问了开发人员:https://github.com/dotnet/aspnetcore/issues/30128。
这里是一个简短的总结:
“SignalR 上的消息与 TCP 一样可靠。基本上这意味着要么您收到消息,要么连接关闭。在这两种情况下,客户端的通道都将完成。”
并且:
“是的,它不应该永远挂起。它要么发送完整的消息,要么断开连接。无论哪种方式,挂起都是客户端中的错误”
我正在使用 System.Threading.Channel
和 .NET 客户端进行 SignalR 服务器到客户端的流式传输。用法是相当基础的,类似于介绍 docs.
集线器代码类似这样:
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
}
}
当我的集线器方法完成流式传输时,它会在其 ChannelWriter
上调用 Complete()
。据推测,SignalR 在内部看到对相应 ChannelReader
的 Complete
调用,将其转换为内部 SignalR 消息并将其传递给客户端。然后,客户端自己的 ChannelReader
被 SignalR 标记为完成,我的客户端代码在流上完成自己的工作。
从服务器到客户端的“完成”通知是否保证被传送?在集线器向客户端广播非流式消息的其他情况下,它通常“触发并忘记”,但我必须假设在流媒体 Channel
上调用 Complete
已确认交付,否则客户端可能处于持有流媒体 ChannelReader
的状态在服务器认为流已关闭时无限期打开。
这个问题不太重要,但我问的原因是我试图缩小这样一种情况,即使用 SignalR 流接口的数据流管道偶尔会挂起,这似乎是唯一的一点它挂在 SignalR 客户端的某个地方。
我在 github 上询问了开发人员:https://github.com/dotnet/aspnetcore/issues/30128。
这里是一个简短的总结:
“SignalR 上的消息与 TCP 一样可靠。基本上这意味着要么您收到消息,要么连接关闭。在这两种情况下,客户端的通道都将完成。”
并且:
“是的,它不应该永远挂起。它要么发送完整的消息,要么断开连接。无论哪种方式,挂起都是客户端中的错误”