1

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

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

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);

任何帮助表示赞赏。

4

3 回答 3

5

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

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

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

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

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

于 2013-02-07T07:24:02.507 回答
2

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

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

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

于 2013-02-07T07:23:51.757 回答
2

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

  • 使用一些“标题”值,(例如)指示下一个块中的字节数;例如,您可以使用固定的 32 位整数计数器并存储 [0 0 0 1 65 0 0 0 2 66 67] 其中 0 0 0 1 是 big-endian1意思是“要读取 1 个字节”,而 65 是A, ETC。
  • 哨兵价值观;例如,由于这是一个文本协议,您可能可以使用 nil 值 (0) 或换行符结束每个块;所以 [65 0 66 67 0] 或 [65 10 66 67 10]
于 2013-02-07T07:24:43.273 回答