Проблема отправки файла TCP в.NET, сокет NetworkStream

Я использую следующий код для отправки файла через TCP.

Если я отправляю много раз один и тот же файл последовательно, чтобы проверить, является ли он надежным, я получаю первый файл правильно, а другой испортился.

Все испорченные файлы имеют одинаковые неправильные байты, и если я сплю (некоторое время), все файлы передаются правильно. Я заметил, что должен создать новый буфер во время чтения моего файла, чтобы все было сделано правильно. Но я не понимаю почему.

Я боюсь, что мое решение восстановить буфер могло бы просто скрыть еще одну серьезную проблему. Любое предложение?

using(var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
    using(var binaryReader = new BinaryReader(fileStream))
    {
        var _sendingBuffer = new byte[BUFFER_SIZE];

        int length = (int)fileStream.Length;
        int bytesRead = 0;

        //Ensure we reached the end of the stream regardless of encoding
        while (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
        {
            bytesRead = binaryReader.Read( _sendingBuffer, 0, _sendingBuffer.Length);

            _socket.BeginSend(_sendingBuffer, 0, bytesRead, SocketFlags.None, SendFileCallback, null);

            //without this i received some messed up data
            _sendingBuffer = new byte[BUFFER_SIZE];
        }    
    }
}

1 ответ

Решение

BeginSend это асинхронная операция Он будет гарантированно запущен только после того, как вы позвоните, он не будет завершен немедленно. Пока сокет отправляет переданные данные, эти данные не должны быть изменены. О завершении операции будет сообщено через AsyncCallback параметр обратного вызова.

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

Другие способы решения проблемы:

  • Используйте блокировку Socket.Send функция, которая будет блокировать, пока не будут отправлены все данные и буфер может быть использован повторно. Это также значительно облегчит вашу обработку ошибок, потому что ошибка не будет отображаться через AsyncCallback,
  • Сделайте вашу полную программу действующей асинхронно, например, используя функции асинхронной задачи C#5 и функции async/await. Поэтому:
    1. Сначала прочитайте одну часть файла асинхронно.
    2. Когда асинхронное чтение заканчивается, отправьте его асинхронно через сокет
    3. Когда это завершится и появится больше данных для чтения, вернитесь к 1.
Другие вопросы по тегам