Search code examples
c#.netstreamblocking

Is any blocking Read method available for Stream?


I am writing an application in C# to open a terminal to a Docker container remotely via a web application. I need to read the stream returned by the Docker.NET client and forward the read bytes via a web socket.

If I call Stream.Read and there is no data available, it simply returns 0 without waiting for data to be available. I spent a while looking for a blocking Read call but couldn't find any. I know .NET has Console.Read() which keeps waiting for input in stdin. How does it achieve this blocking call - do they use a loop or is there any blocking method available?

I wrote below code using a while loop and check if any bytes were read. Is it necessary to add Thread.Sleep or Task.Delay to avoid it consuming too much 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);
    }
}

Solution

  • Stream.Read is a blocking call, and according to the documentation it should not return unless it either has some data, or reached the end of the stream:

    Read returns 0 only if zero bytes were requested or when there is no more data in the stream and no more is expected (such as a closed socket or end of file). An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.

    So the sleep should not be needed. However, your code to read data is just wrong, and will only read at most one buffer worth of data. See How do I convert a Stream into a byte[] to read all of the data from the stream.

    Ofc, with third party streams, non-conforming implementations are always possible. So you might want to confirm that all the data are actually read.