通过 TCP 接收数据:MemoryStream 包含比预期更多的数据

Receiving data via TCP: MemoryStream contains more data than expected

我托管了一个服务器,该服务器从远程 TCP 客户端(我也控制)接收数据。这是处理传入数据的方法:

private static async Task ReceiveDataFromRemoteSocket(
    Socket socket,
    int numBytesExpectedToReceive)
{
    int numBytesLeftToReceive = numBytesExpectedToReceive;

    using (MemoryStream memoryStream = new MemoryStream(numBytesExpectedToReceive))
    {
        byte[] dataBuffer = new byte[1024];

        ArraySegment<byte> dataBufferSegment = new ArraySegment<byte>(dataBuffer);          
        int totalBytesReceived = 0;

        while (numBytesLeftToReceive > 0)
        {
            Array.Clear(dataBuffer, 0, dataBuffer.Length);

            int numBytesReceived = await socket.ReceiveAsync(dataBufferSegment, SocketFlags.Partial);
            Console.WriteLine($"Received {numBytesReceived} bytes of data at {DateTime.UtcNow.ToShortTimeString()}.");

            totalBytesReceived += numBytesReceived;

            memoryStream.Write(
                dataBuffer,
                0,
                numBytesLeftToReceive < dataBuffer.Length ? numBytesLeftToReceive : dataBuffer.Length);
            numBytesLeftToReceive -= numBytesReceived;
        }
        Console.WriteLine($"Total number of bytes received, according to tally: {totalBytesReceived}.");
        Console.WriteLine($"Memory stream: Contains {memoryStream.Length} bytes' worth of data.");
    }
}

numBytesExpectedToReceive 是从 header.

检索到的信息

这是我控制台上的输出:


Accepted connection request from XX.XX.XXX.XXX:56767 at 4/30/2019 10:39:11 AM.
Expecting to receive 41898 bytes' worth of data from XX.XX.XXX.XXX:56767.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 416 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 96 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 1024 bytes of data at 10:39 AM.
Received 512 bytes of data at 10:39 AM.
Total number of bytes received, according to tally: 41984.
Memory stream: Contains 43434 bytes' worth of data.

如您所见,内存流包含 43434 字节的数据,尽管我预计它只包含 41984 字节。

这会导致很多问题,例如如果我通过编写 new ZipArchive(memoryStream); 创建 ZipArchive 的新实例,我最终会得到一个 InvalidDataException,即使我知道我的远程 TCP 客户端发送了一个有效的 zip 文件。

  1. 为什么内存流包含的字节数比通过 TCP 实际接收到的字节数多?
  2. 如何删除这些 "junk data"(因为没有更好的术语),以便我可以成功地重建发送给我的数据,例如通过将内存流传递给 ZipArchive 构造函数?

问题出在你写数据的地方:

memoryStream.Write(
            dataBuffer,
            0,
            numBytesLeftToReceive < dataBuffer.Length ? numBytesLeftToReceive : dataBuffer.Length);

你完全忽略了你收到的数量,而是检查是否有比自助餐大小更多的数据要接收,如果有你写整个缓冲区。

您可以在输出中看到有时您没有收到完整的缓冲区。然而你仍然写了整个缓冲区。

始终根据您收到的金额来写。不要根据数据的长度做任何奇怪的比较:

memoryStream.Write(
            dataBuffer,
            0,
            numBytesReceived);