C# Write()和Read()从NetworkStream中读取原始字节,数据在某些字节上存在差异

C# Write()和Read()从NetworkStream中读取原始字节,数据在某些字节上存在差异,c#,arrays,networkstream,C#,Arrays,Networkstream,我已经编写了一些代码,用于在发送之前使用已知大小的NetworkStream发送byte[]数组,但是发送的数据和接收的数据在某些位置上是不同的 MAXSIZE是我要发送的数据的已知大小 public static void SendBytes(TcpClient clientSocket, byte[] outStream) { Debug.WriteLine("SendBytes() number of bytes: " + outStream.Length.

我已经编写了一些代码,用于在发送之前使用已知大小的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

流。Read
返回一个值,该值指示实际读取的数据量。决不能保证与您要求的金额相同。忽略此值将产生风险


如果您愿意为整个流分配内存,为什么不直接复制到
MemoryStream
并从中获取完整的缓冲区呢
Stream.CopyTo
Stream.CopyToAsync
是很好的高级抽象,可以简化这一过程。

您很可能看到由于数据包结构造成的垃圾;TCP只保证正确的字节将以正确的顺序到达(或流失败)——它没有说明它们到达的块。正因为如此,您必须:

  • Read
    捕获返回值,只处理任何块中的那么多字节
  • 执行您自己的帧-即,将流成批处理为消息,而不依赖于片段如何到达
  • 如果您的消息总是固定大小,那么“2”将变为“缓冲数据,直到我至少有N个字节,然后以N个字节为单位处理数据,保留剩余的数据,然后恢复缓冲”。但在一般情况下,它可能是“缓冲,直到我看到一个哨兵值,如换行符”,或“缓冲,直到我有一个完整的头,然后解析头,看看需要多少数据,然后缓冲,直到我有那么多数据”

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

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

    byte[]bytesFrom=新字节[MAX_SIZE];
    int未决=最大大小,读取,偏移=0;
    而(未完成的>0&(read=networkStream.read(bytesFrom、offset、未完成的))>0)
    {
    偏移量+=读取;
    杰出-=阅读;
    }
    如果(未完成!=0)抛出新的EndOfStreamException();
    

    这将创建一个读取循环,该循环从完全填充字节,或因异常而失败。

    关于您的第二个问题:我假设这是一个多消息协议,他们只希望接收特定的amount@MarcGravell是的,我想你可能是对的。我假设的是一个事务,不是答案,但是你应该在变量名上多加小心。例如,<代码>外流不是一个流,所以请考虑一些类似于<代码>数据> /代码>或<>代码>数据> <代码> >如果您喜欢更明确的话,谢谢。您清楚地解释了问题并提供了一个很好的解决方案。