首页 > 解决方案 > 通过 TCP 接收数据:MemoryStream 包含比预期更多的数据

问题描述

我托管了一个服务器,它从远程 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是从标头中检索的信息。

这是我控制台上的输出:


已于 2019 年 4 月 30 日上午 10:39:11 接受来自 XX.XX.XXX.XXX:56767 的连接请求。
期望从 XX.XX.XXX.XXX:56767 接收 41898 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 416 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 96 个字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 1024 字节的数据。
上午 10:39 收到 512 字节的数据。
接收到的字节总数,根据计数:41984。
内存流:包含 43434 字节的数据。

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

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

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

标签: c#.nettcptcpclientmemorystream

解决方案


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

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

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

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

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

memoryStream.Write(
            dataBuffer,
            0,
            numBytesReceived);

推荐阅读