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

时间:2019-04-30 10:58:02

标签: c# .net tcp tcpclient 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日接受了来自XX.XX.XXX.XXX:56767的连接请求   上午10:39:11。
期望从中接收价值41898字节的数据   XX.XX.XXX.XXX:56767。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到416字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到96个字节的   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到1024个字节的数据。   
在10:39 AM接收到1024个字节的数据。
收到的1024个字节   上午10:39的数据。
在10:39 AM接收到512字节的数据。   
收到的总字节数,根据提示:   41984。
内存流:包含43434个字节的数据。

如您所见,内存流包含43434字节的数据,即使我希望它仅包含41984字节也是如此。

这会引起很多问题,例如如果我通过写ZipArchive创建了new ZipArchive(memoryStream);的新实例,即使我知道我的远程TCP客户端已经发送了一个有效的zip文件,我仍然以InvalidDataException结尾。

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

1 个答案:

答案 0 :(得分:3)

问题出在这里,您可以在其中写入数据:

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

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

有时您会在输出中看到没有收到完整的缓冲区。但是,您仍然要编写整个缓冲区。

始终根据收到的金额写信。不要根据数据的长度进行任何奇怪的比较:

memoryStream.Write(
            dataBuffer,
            0,
            numBytesReceived);