在块中写入并在流对象c#中接收块

时间:2013-02-07 07:19:38

标签: c# stream

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

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

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

感谢任何帮助。

3 个答案:

答案 0 :(得分:5)

是的,你有一个 - 只是一个字节序列 - 但你把它视为不是一个流;好像它是一个面向消息的协议。

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

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

其中第二个可能是最简单的,但有一个限制,你需要知道在开始发送之前消息有多大。第三个选项通过具有可变数量的块来绕过它。如果可能的话,我个人会避免使用第一个选项 - 除非你有一些自然的“消息结束”令牌,你永远不想将其作为数据包含在消息中,你必须开始研究逃避计划,这是一个痛苦......而且也很难读取数据。

当然,你不必从头开始做所有这些。如果你的两端都有.NET,你可以使用支持长度前缀字符串的BinaryReaderBinaryWriter,并且还有很多序列化框架,通常以某种形式处理这个或者其他。 (我个人的偏好是Protocol Buffers,因为它是高效的,独立于平台的,以及我在工作中使用的东西。有两个常见的.NET端口 - one by myselfone by Marc Gravell。)

答案 1 :(得分:2)

顾名思义,您正在使用的是一个流。一方的电话Write与另一方的电话Read之间无法保证1-1对应。

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

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

答案 2 :(得分:2)

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

  • 使用一些"标题" value,(例如)表示下一个块中的字节数;例如,您可以使用固定的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]