当 NetworkStream.Read(byte[], int, int) 需要返回 -1 时,它会中止()它正在运行

本文关键字:int 运行 byte Read NetworkStream 返回 | 更新日期: 2023-09-27 18:33:47

        NetworkStream stream = socket.GetStream();
        if (stream.CanRead)
        {
            while (true)
            {
                int i = stream.Read(buf, 0, 1024);
                result += Encoding.ASCII.GetString(buf, 0, i);
            }
        }

上面的代码旨在在单独的线程上运行时从TcpClient检索消息。 Read方法工作正常,直到它应该返回 -1 以指示没有可读取的内容;相反,它只是终止它正在运行的线程,没有任何明显的原因 - 使用调试器跟踪每个步骤显示它只是在该行之后立即停止运行。

我也尝试用try ... catch封装它,但没有多大成功。

可能是什么原因造成的?

编辑:我试过了

        NetworkStream stream = socket.GetStream();
    if (stream.CanRead)
    {
        while (true)
        {
            int i = stream.Read(buf, 0, 1024);
            if (i == 0)
            {
                break;
            }
            result += Encoding.ASCII.GetString(buf, 0, i);
        }
    }

多亏了@JonSkeet,但问题仍然存在。线程在该read行终止。

编辑2:我像这样修复了代码,它起作用了。

    while (stream.DataAvailable)
    {
        int i = stream.Read(buf, 0, 1024);
        result += Encoding.ASCII.GetString(buf, 0, i);
    }

我认为问题很简单,只是没有想得足够彻底。感谢大家的收看!

当 NetworkStream.Read(byte[], int, int) 需要返回 -1 时,它会中止()它正在运行

不,当没有要读取的内容时,Stream.Read返回 0,而不是 -1:

返回值
读入缓冲区的总字节数。如果当前没有可用的字节数,则此值可以小于请求的字节数,如果已到达流的末尾,则此值可能小于零 (0)。

我的猜测是,实际上,没有抛出异常并且线程没有被中止 - 但它只是永远循环。如果在调试器中单步执行,应该能够看到这一点。无论发生什么,你的"快乐"终止条件永远不会被击中......

由于您正在尝试从流中读取 ASCII 字符,因此请查看以下内容,作为一种可能更简单的方法:

public IEnumerable<string> ReadLines(Stream stream)
{
    using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
    {
        while (!reader.EndOfStream)
            yield return reader.ReadLine();
    }
}

虽然这可能不完全是您想要的,但要点是:

  • 使用StreamReader为您完成所有艰苦的工作
  • 使用 while 循环和 !reader.EndOfStream 循环遍历流
  • 如果您希望将区块读取到缓冲区中并追加到结果,则仍可以使用reader.Read(buffer, 0, 1024)。请注意,这些将是char[]块而不是byte[]块,这可能是您想要的。
在我看来

,它只是在阻塞 - 即等待流的末尾。为了使它返回一个非正数,必须关闭流,即调用方不仅发送了数据,而且关闭了他们的出站套接字。否则,系统无法区分"等待数据包到达"和"流结束"。

如果调用方只发送一条消息,则应在发送后关闭其出站套接字(他们可以保持入站套接字打开以进行回复)。

如果调用方正在发送多条消息,则必须使用成帧方法来读取单个子消息。在基于文本的协议的情况下,这通常意味着"寻找换行符"。