读取-填充整个缓冲区的正确方式(否则抛出异常)

本文关键字:方式 抛出异常 填充 缓冲区 读取 | 更新日期: 2023-09-27 18:24:03

NetworkStream.Read方法文档指出,它在两种情况下返回零:

  • 如果没有可供读取的数据,Read方法将返回0
  • 如果远程主机关闭连接,并且接收到所有可用数据,Read方法立即完成并返回零字节

还有以下观察结果:

通过调用CanRead属性检查NetworkStream是否可读。如果您尝试从不可读的NetworkStream中读取,则会收到IOException。

我很困惑。我怎么知道我可以继续阅读,或者我应该停止尝试阅读?

采取以下采样方法:

void Receive(byte[] buffer)
{
    int idx = 0;
    while (idx < buffer.Length)
    {
        if (input.CanRead)
        {
            int read = input.Read(buffer, idx, buffer.Length - idx);
            if (read == 0)
            {
                // ???
            }
            idx += read;
        }
        else
        {
            throw new MyLibConnectionClosedException("Cannot receive because the connection was closed");
        }
    }
}

它应该填满整个缓冲区,或者抛出异常(如果连接已关闭或丢失)。正确的方法是什么?

读取-填充整个缓冲区的正确方式(否则抛出异常)

采取基于证据的方法来确定事实。。。如果您查看依赖于方法Stream.InternalCopyToStream.CopyTo的源代码,您将看到以下用于将一个流复制到另一个流的代码:

byte[] buffer = new byte[bufferSize];
int read;
while ((read = Read(buffer, 0, buffer.Length)) != 0)
    destination.Write(buffer, 0, read);

这让我非常清楚,0代表流的结束,而不是"现在没有什么可读的"。

任何关于0的返回值具有第二含义的建议都是不正确的,因为这会使CopyTo的实现不正确。

简而言之,要将流读取到底,请继续读取,直到Read返回0(或抛出异常)。