【问题标题】:Avoid NetworkStream read block避免 NetworkStream 读取块
【发布时间】:2015-12-31 16:55:53
【问题描述】:

目前我一直在开发一个使用 TcpClient 从服务器接收数据的程序。我的问题是,每当我读取流直到我可以我的客户端停止工作时,它就会冻结。我想保持与服务器的持续连接,但是在我的 while 函数运行两次之后,第三个循环不执行读取,并且永远不会返回任何内容。

As this answer states that I'm correct

如何中断或返回这个 while 循环,或者以某种方式绕过读取块?

using (NetworkStream stream = client.GetStream())
{
    byte[] data = new byte[2048];
    using (MemoryStream ms = new MemoryStream())
    {

        int numBytesRead;
        while ((numBytesRead = stream.Read(data, 0, data.Length)) > 0)
        {
            ms.Write(data, 0, numBytesRead);
        }
        return ms.ToArray();
    }
}

【问题讨论】:

  • 我无法从您的代码和描述中判断Read 调用是否真的存在问题,但目前假设获取下一批数据需要一段时间,在如此长的阅读过程中保持 GUI 响应的唯一方法是在单独的线程上建立网络。
  • 实际上,我将限定我上面的评论:你也可以使用BeginRead/EndRead
  • 我确实测试过它,服务器发送一个长度为 1654 的字节,然后 while 读取它两次:1460 和 194,即 1654。但是当第三个循环运行时,它会检查如果数据为 0,则循环就卡在那里,不再启动,只是等待更多数据。
  • 你的 while 循环很糟糕。 TCP 可以发送零字节的数据报。您必须测试可以是以下任何(或组合)的数据结尾:1)Ascii:终止字符,如'\ n'。 2) Ascii 或 Binary:将字节计数添加到消息的开头,然后读取,直到收到所有字节。 3) Ascii 或 Binary:固定长度消息。每种类型的消息都有一个已知的长度。
  • 你应该这样做while (client.Connected && (numBytesRead = stream.Read(data, 0, data.Length)) > 0)

标签: c# tcpclient


【解决方案1】:

我会尽力给你一些提示。如果您不希望 UI 被冻结,您应该将此代码放在单独的线程上,或者将其作为异步任务运行,正如 Wouter 评论的那样。在我看来,如果您既不知道您期望接收多少字节,也不知道它们何时来找您,这将是更好的方法。正如你所说,如果你想让这个任务长时间运行,线程将是一个很好的解决方案。

尽管如此,如果可能的话,您应该关注两件事:您的 TcpClient ReadTimeout 属性和您通过 stream.Read() 的第三个参数的预期长度。这意味着您将被阻止 X 毫秒,直到您收到所需的数量。我在事务服务器上做了很多工作,在这些网络之间传输的数据包以包的长度为前缀。如果是这种情况,我建议先读取前缀,然后计算剩余要读取的字节数,然后执行最后一次读取操作。

希望这有帮助,这是我的第一个答案。

【讨论】:

  • 问题是读取卡住了,而我已经收到了数据。我会尝试检查 readtimeout。
  • 如果卡在 Read() 调用上,如何确定已收到数据?很抱歉,我第一眼没看懂你的问题。
  • "我确实测试过了,服务器发送一个长度为 1654 的字节,然后 while 读取它两次:1460 和 194,即 1654。但是当第三个循环运行时,它会检查数据是否为0,循环只是卡在那里,不再启动,只是等待更多数据“服务器说长度也是1654
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多