Получение данных через TCP: MemoryStream содержит больше данных, чем ожидалось - PullRequest
0 голосов
/ 30 апреля 2019

Я размещаю сервер, который получает данные от удаленного 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 - информация, полученная из заголовка.

Вот вывод на моей консоли:


Принят запрос на подключение от XX.XX.XXX.XXX:56767 от 30.04.2009 10:39:11
Ожидается получение данных от 41898 байт XX.XX.XXX.XXX:56767.
Получено 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 байт данных в 10:39.
Общее количество полученных байтов, согласно подсчету: 41984.
Поток памяти: содержит данные объемом 43434 байта.

Как видите, поток памяти содержит 43434 байта данных, хотя я ожидаю, что он будет содержать только 41984 байта.

Это вызывает много проблем, например, если я создаю новый экземпляр ZipArchive, записывая new ZipArchive(memoryStream);, я получаю InvalidDataException, хотя я знаю, что мой удаленный TCP-клиент отправил действительный zip-файл.

  1. Почему поток памяти содержит больше байтов, чем фактически получено через TCP?
  2. Как я могу удалить эти «ненужные данные» (из-за отсутствия лучшего термина), чтобы я мог успешно восстановить данные, которые были отправлены мне, например, путем передачи потока памяти в конструктор ZipArchive?

1 Ответ

3 голосов
/ 30 апреля 2019

Проблема здесь, когда вы пишете данные:

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

Вы полностью игнорируете сумму, которую вы получили, вместо этого вы просто проверяете, есть ли больше данных, которые должны быть получены, чем размер буфера, и если вы пишетевесь буфер.

Вы можете видеть в своих выходных данных, что иногда вы не получаете полный буфер.Тем не менее, вы все еще пишете весь буфер.

Всегда пишите в зависимости от суммы, которую вы получили.Не делайте никаких странных сравнений на основе длины данных:

memoryStream.Write(
            dataBuffer,
            0,
            numBytesReceived);
...