【问题标题】:Write() and Read() raw bytes from NetworkStream, data is difference at some bytes来自 NetworkStream 的 Write() 和 Read() 原始字节,数据在某些字节处有所不同
【发布时间】:2019-10-09 23:42:37
【问题描述】:

我已经编写了一些代码,用于在发送之前使用具有已知大小的 NetworkStream 发送 byte[] 数组,但是发送的数据和接收的数据在某些位置是不同的。

MAXSIZE 是我要发送的数据的已知大小。

    public static void SendBytes(TcpClient clientSocket, byte[] outStream)
    {
        Debug.WriteLine("SendBytes() number of bytes: " + outStream.Length.ToString());

        NetworkStream serverStream = clientSocket.GetStream();

        serverStream.Write(outStream, 0, outStream.Length);
        //serverStream.Flush();
    }

    public static byte[] ReceiveBytes(TcpClient clientSocket, int MAX_SIZE)
    {
        Debug.WriteLine("[" + DateTime.Now.ToString("G") + "] - " + "ReceiveBytes() started.");

        NetworkStream networkStream = clientSocket.GetStream();

        byte[] bytesFrom = new byte[MAX_SIZE];
        clientSocket.ReceiveBufferSize = MAX_SIZE;

        networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);

        Debug.WriteLine("[" + DateTime.Now.ToString("G") + "] - " + "ReceiveBytes(), received number of raw bytes: " + bytesFrom.Length.ToString());

        return CommonUtils.SubArray(bytesFrom, 0, MAX_SIZE);
    }

如果发送数据(十六进制字节):a7 fc d0 51 0e 99 cf 0d 00 ,接收到的数据为:a7 fc d0 51 0e 99 cf 0d 53

【问题讨论】:

  • 不是一个答案,但你真的应该更加小心你的变量名。例如,outStream 不是一个流,因此如果您希望更明确一些,请考虑使用 datadataToSend 之类的内容。

标签: c# arrays networkstream


【解决方案1】:

由于数据包结构,您很可能会看到垃圾; TCP 只保证正确的字节将以正确的顺序到达(或流失败) - 它没有说明它们到达的 chunks。因此,您至关重要

  1. Read 获取返回值,并且只处理来自任何块的那么多字节
  2. 执行您自己的框架 - 即将流分批成消息,而与片段的到达方式无关

如果您的消息总是固定大小,那么“2”将变为“缓冲数据,直到我有至少 N 个字节,然后以 N 块处理数据,保留剩余的任何内容,然后恢复缓冲”。但在一般情况下,它可能是“缓冲直到我看到一个标记值,例如换行”,或者“缓冲直到我有一个完整的标题,然后解析标题以查看预期有多少数据,然后缓冲直到我有那么多数据”。

有一些工具和实用程序可以帮助简化去帧和处理积压工作 - 例如,使用新的“管道”API,它只是检查管道并告诉管道您想要消耗多少的情况(而不是它给你一切,而你现在无法拒绝数据)-但是从Stream切换到“管道”对于大多数人来说是相当多的变化。

在您的情况下,您可能可以使用:

byte[] bytesFrom = new byte[MAX_SIZE];
int outstanding = MAX_SIZE, read, offset = 0;
while (outstanding > 0 && (read = networkStream.Read(bytesFrom, offset, outstanding)) > 0)
{
    offset += read;
    outstanding -= read;
}
if (outstanding != 0) throw new EndOfStreamException();

这会创建一个完全填充bytesFrom 的读取循环,否则会因异常而失败。

【讨论】:

  • 谢谢。您清楚地解释了问题并提供了很好的解决方案。
【解决方案2】:

Stream.Read 返回一个值,该值指示实际读取了多少数据。绝不保证与您要求的金额相同。忽略此值后果自负。

如果您乐于为整个流分配内存,为什么不直接复制到 MemoryStream 并从中获取完整的缓冲区? Stream.CopyToStream.CopyToAsync 是很好的高级抽象,让这一切变得简单。

【讨论】:

  • 是您的第二个问题:我假设这是一个多消息协议,他们只想收到特定数量
  • @MarcGravell 是的,我认为您可能是对的。我假设是单笔交易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多