c# - NetworkStream.Length 替代

标签 c# .net sockets networkstream

我正在使用网络流在网络中传递短字符串。
现在,在接收端我遇到了一个问题:
通常我会这样阅读

  1. 查看数据是否可用
  2. 获取可用数据的数量
  3. 将那么多字节读入缓冲区
  4. 将缓冲区内容转换为字符串。

在假设所有提供的方法都按预期工作的代码中,它看起来像这样:

NetworkStream stream = someTcpClient.GetStream();
while(!stream.DataAvailable)
    ;

byte[] bufferByte;
stream.Read(bufferByte, 0, stream.Lenght);
AsciiEncoding enc = new AsciiEncoding();
string result = enc.GetString(bufferByte);

但是,MSDN 表示 NetworkStream.Length并没有真正实现,调用时总是会抛出异常。
由于传入数据的长度各不相同,因此我无法对期望的字节数进行硬编码(这也是魔数(Magic Number)反模式的情况)。

问题:
如果我无法获得可用于读取的字节数的准确计数,那么我如何才能正确地从流中读取,而不冒 NetworkStream.Read 内的各种异常风险? ?

编辑:
尽管提供的答案会导致更好的整体代码,但我仍然想分享我遇到的另一个选项:
TCPClient.Available给出可供读取的字节数。我知道必须有一种方法来计算自己收件箱中的字节数。

最佳答案

无法保证连接一侧对 Read 的调用与另一侧对 Write 的调用 1-1 匹配。如果您要处理可变长度的消息,则由向接收方提供此信息。

执行此操作的一种常见方法是首先计算出您要发送的消息的长度,然后先发送该长度信息。在接收方,您首先获得长度,然后您知道要分配多大的缓冲区。然后在循环中调用 Read,直到读取到正确的字节数。请注意,在您的原始代码中,您当前忽略 Read 的返回值,它告诉您实际读取了多少字节。在一次调用和返回中,这可能低至 1,即使您要求超过 1 个字节。

另一种常见的方法是决定消息的“格式”——例如消息编号 1 的长度始终为 32 字节,并且具有 X 结构,消息编号 2 的长度始终为 51 字节,并且具有 Y 结构。使用这种方法,不是在发送消息之前发送消息 length,而是发送格式信息 - 首先发送“这里有一条类型 1 的消息”,然后再发送消息。

另一种常见的方法(如果适用)是使用某种形式的哨兵 - 如果您的消息永远不会包含一个值为 0xff 的字节,那么您将扫描接收到的字节,直到您收到一个 0xff 字节,然后该字节之前的所有内容都是您要接收的消息。

但是,无论您想做什么,无论是上述方法之一还是其​​他方法,都取决于让您的发送方和接收方一起工作以允许接收方发现每个消息。


我忘记说了,但是改变周围一切的更进一步的方法是 - 如果你想交换消息,并且不想做任何上述的摆弄,那么切换到一些东西在更高级别工作 - 例如WCF、HTTP 或其他系统,这些系统已经负责消息框架,然后您可以专注于如何处理您的消息。

关于c# - NetworkStream.Length 替代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23602323/

相关文章:

.net - 在 .NET 中读取 UTF8 编码的命令行 (C#)

java - 通过套接字 Java 发送字节数组,然后发送字符串,然后发送字节

c++ - c++中读取函数的一个问题

c# - 如何在 .NET 中创建虚拟网络适配器?

c# - TcpClient 无法通过流正确发送数据

c# - 调试器未附加到进程

c# - 创建从 C 到 C# 的混合模式 C++ 桥?

c# - 如何修复标签未显示在 ListView 中的问题?

c# - Json.Net PopulateObject - 根据 ID 更新列表元素

c# - 什么会阻止在 C# 语言中向枚举添加属性?