来自NetworkStream的Write()和Read()原始字节,某些字节的数据存在差异

时间:2019-05-23 11:46:00

标签: c# arrays networkstream

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

2 个答案:

答案 0 :(得分:2)

由于数据包的结构化,很可能您会看到垃圾; TCP仅保证正确的字节将以正确的顺序到达(否则将导致流失败)-它没有提及到达它们的。因此,您重要

  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,否则会因异常而失败。

答案 1 :(得分:1)

read -p 'Email:' USERMAIL返回一个值,该值指示 实际上 读取了多少数据。绝不保证与您要求的金额相同。忽略此值,后果自负。

如果您愿意为整个流分配内存,为什么不只复制到Stream.Read中并从中获取全部缓冲区呢? MemoryStreamStream.CopyTo是很好的高级抽象,可以简化此工作。