我正在用 C# 编写一个应用程序,以通过 Web 应用程序远程打开 Docker 容器的终端。我需要读取 Docker.NET 客户端返回的流并通过 Web 套接字转发读取的字节。
如果我调用 Stream.Read 并且没有可用数据,它只会返回 0,而不等待数据可用。我花了一段时间寻找阻塞 Read 调用,但没有找到。我知道 .NET 有
Console.Read()
,它会一直等待标准输入中的输入。它是如何实现这种阻塞调用的 - 他们使用循环还是有可用的阻塞方法?
我使用 while 循环编写了下面的代码,并检查是否读取了任何字节。是否需要添加Thread.Sleep或Task.Delay以避免消耗太多CPU?
async Task ForwardStreamViaWebSocket(Stream stream, WebSocket webSocket, CancellationToken cancellationToken)
{
var buffer = new byte[1024];
while (!cancellationToken.IsCancellationRequested)
{
var bytesRead = 0;
// Any blocking Read method available instead of looping?
while (bytesRead == 0)
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
Thread.Sleep(100); // Is this really required?
}
var arraySegment = new ArraySegment<byte>(buffer, 0, bytesRead);
await webSocket.SendAsync(arraySegment, WebSocketMessageType.Binary, false, cancellationToken);
}
}
Stream.Read 是一个阻塞调用,根据 documentation 它不应该返回,除非它有一些数据,或者到达流的末尾:
仅当请求零字节或流中不再有数据并且预计不再有数据(例如关闭的套接字或文件结尾)时,Read 才会返回 0。即使尚未到达流的末尾,实现也可以自由地返回比请求更少的字节。以从流中读取所有数据。所以不需要睡眠。但是,您读取数据的代码是错误的,并且最多只能读取一个缓冲区的数据。请参阅
如何将 Stream 转换为 byte[]