【问题标题】:Writing in Blocks and receiving in blocks in stream object c#在流对象c#中写入块并接收块
【发布时间】:2013-12-30 06:31:56
【问题描述】:

我有两个应用程序,一个在服务器上,一个在客户端。

在服务器端,我像这样写入流。

NetworkStream stream = client.GetStream();

byte[] msg = System.Text.Encoding.ASCII.GetBytes(messageSent);

stream.Write(msg, 0, msg.Length);
stream.Write(msg, 0, msg.Length);

我正在一个一个地在流中写入多个字符串。字符串的长度是可变的,最大长度约为 500

问题:

如何在客户端读取块

有时我会得到组合字符串

就像我发送了 A、B、C 一样

在客户端我收到了 A,BC

我是这样的客户:

bytes = stream.Read(data, 0, data.Length);

感谢任何帮助。

【问题讨论】:

    标签: c# stream


    【解决方案1】:

    是的,你有一个——只是一个字节序列——但你把它当作不是一个流;就好像它是一个面向消息的协议一样。

    从根本上说,通过简单的基于流的通信,没有什么固有可以将流分解为消息。如果你想这样做,你需要在上面构建一个层。执行此操作的常用方法有以下三种:

    • 使用您在阅读时发现的“消息结束”标记
    • 在每条消息前使用长度前缀
    • 使用一种混合方式,其中每条消息可以由多个块组成,每个块都带有长度前缀,而长度为 0 的块表示“消息结束”

    第二个可能是最简单的,但有一个限制,即您需要在开始发送之前知道消息的大小。第三个选项通过具有可变数量的块来解决这个问题。如果可能的话,我个人会避免第一个选项 - 除非您有一些自然的“消息结束”令牌,您永远不会想要将其作为数据包含在消息中,你必须开始制定一个转义方案,这很痛苦……而且读取数据也更难。

    当然,您不必从头开始执行所有这些操作。如果两端都有.NET,则可以使用支持长度前缀字符串的BinaryReaderBinaryWriter,并且周围也有很多序列化框架,它们通常以某种形式处理这个问题。 (我个人的偏好是 Protocol Buffers,因为它高效、独立于平台,而且我在工作中使用。有两个常见的 .NET 端口 - one by myselfone by Marc Gravell。)

    【讨论】:

    • 当我们说令牌时,它表示任何特殊符号,如“|”最后登录并在客户端将其拆分为消息或其他内容。我发现这种分裂就像编程之死
    • @Moons:是的,没错。这在各个方面都是一种痛苦——如果你能做到的话,长度前缀往往会更好。
    【解决方案2】:

    顾名思义,您使用的是流。不能保证一方面对Write 的调用与另一方面对Read 的调用之间存在1-1 对应关系。

    一种常见的发送消息的方法是先发送消息长度(例如,一个转换为 4 字节的 int),然后发送消息。

    然后(在接收端)读取该长度,(如果需要)分配该大小的缓冲区,然后重复调用Read,直到缓冲区被填满。

    【讨论】:

      【解决方案3】:

      流只是一个字节序列。除了您创建的块之外,没有块的概念。您将需要发明一些附加机制来了解每个块的开始/结束位置。有多种常用方法:

      • 使用一些“header”值,(例如)指示下一个块中的字节数;例如,您可以使用固定的 32 位整数计数器并存储 [0 0 0 1 65 0 0 0 2 66 67] 其中 0 0 0 1 是大端 1 意思是“要读取的 1 个字节”,而65 是A 等。
      • 前哨值;例如,由于这是一个文本协议,您可以用 nil 值 (0) 或换行符结束每个块;所以 [65 0 66 67 0] 或 [65 10 66 67 10]

      【讨论】:

        猜你喜欢
        • 2015-11-24
        • 2023-03-23
        • 2018-11-28
        • 1970-01-01
        • 2020-06-06
        • 1970-01-01
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多