Передача файлов C # TCP - Полупередача изображений - PullRequest
1 голос
/ 05 марта 2011

Я разрабатываю программу клиент-сервер для передачи файлов по протоколу TCP.В настоящее время я могу отправлять текстовые файлы и другие форматы файлов совершенно нормально, например .zip, со всем содержимым на стороне сервера.Однако, когда я передаю .gif, конечный результат - это gif с тем же размером, что и оригинал, но только с частью изображения, показывающей, как будто большинство байтов потеряно или неправильно записано на стороне сервера.

Клиент отправляет серверу пакет заголовка размером 1 КБ с именем и размером файла.Затем сервер отвечает OK, если готов, а затем создает файловый буфер размером с файл, который нужно отправить.

Вот код, демонстрирующий мою проблему:

// Serverside method snippet dealing with data being sent
while (true)
{
   // Spin the data in
   if (streams[0].DataAvailable)
   {
      streams[0].Read(fileBuffer, 0, fileBuffer.Length);
      break;
   }
}
// Finished receiving file, write from buffer to created file
FileStream fs = File.Open(LOCAL_FOLDER + fileName, FileMode.CreateNew, FileAccess.Write);
fs.Write(fileBuffer, 0, fileBuffer.Length);
fs.Close();
Print("File successfully received.");
// Clientside method snippet dealing with a file send
while(true)
{
   con.Read(ackBuffer, 0, ackBuffer.Length);
   // Wait for OK response to start sending
   if (Encoding.ASCII.GetString(ackBuffer) == "OK")
   {
      // Convert file to bytes
      FileStream fs = new FileStream(inPath, FileMode.Open, FileAccess.Read);
      fileBuffer = new byte[fs.Length];
      fs.Read(fileBuffer, 0, (int)fs.Length);
      fs.Close();
      con.Write(fileBuffer, 0, fileBuffer.Length);
      con.Flush();
      break;
   }
}

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

Я ошибочно считаю, что успешная передача файла так же проста, как преобразование в байты, транспортировка, а затем преобразование обратно в имя файла / тип?

Вся помощь / совет высоко ценится.

Ответы [ 4 ]

1 голос
/ 23 марта 2012

Речь идет не о вашем изображении. Это о вашем коде.

если ваши байты изображения были потеряны или записаны неправильно, это означает, что ваш код передачи файла неправильный и даже будет получен файл .zip или любой другой файл. Это будет исправлено.
Это огромныйошибка установки длины буфера байтов в размере файла.представьте, что вы собираетесь отправить большой файл размером около 1 ГБ ... тогда потребуется 1 ГБ ОЗУ ... для передачи в режиме ожидания вы должны зациклить файл для отправки.

Это способотправлять / получать файлы без ограничений по размеру.

Отправить файл

using (FileStream fs = new FileStream(srcPath, FileMode.Open, FileAccess.Read))
{
        long fileSize = fs.Length;
        long sum = 0;   //sum here is the total of sent bytes.
        int count = 0;
        data = new byte[1024];  //8Kb buffer .. you might use a smaller size also.
        while (sum < fileSize)
        {
            count = fs.Read(data, 0, data.Length);
            network.Write(data, 0, count);
            sum += count;
        }
        network.Flush();
}

Получить файл

long fileSize = // your file size that you are going to receive it.
using (FileStream fs = new FileStream(destPath, FileMode.Create, FileAccess.Write))
{
        int count = 0;
        long sum = 0;   //sum here is the total of received bytes.
        data = new byte[1024 * 8];  //8Kb buffer .. you might use a smaller size also.
        while (sum < fileSize)
        {
            if (network.DataAvailable)
            {
                {
                    count = network.Read(data, 0, data.Length);
                    fs.Write(data, 0, count);
                    sum += count;
                }
            }
        }
}

счастливое кодирование:)

1 голос
/ 05 марта 2011

Когда вы пишете по TCP, данные могут поступать в виде нескольких пакетов. Я думаю, что ваши ранние тесты оказались в одном пакете, но этот файл GIF приходит в 2 или более. Поэтому, когда вы вызываете Read, вы получите только то, что уже получено - вам нужно будет повторно проверять, пока вы не получите столько байтов, сколько указано в заголовке.

Я нашел Руководство Биджа по сетевому программированию большая помощь при работе с TCP.

0 голосов
/ 05 марта 2011

Как уже отмечали другие, данные не обязательно все приходят сразу, и ваш код перезаписывает начало буфера каждый раз через цикл.Более надежный способ записать цикл чтения - это прочитать столько байтов, сколько доступно, и увеличить счетчик, чтобы отслеживать, сколько байтов было прочитано до сих пор, чтобы вы знали, куда поместить их в буфер.Что-то вроде этого работает хорошо:

int totalBytesRead = 0;
int bytesRead;
do
{
    bytesRead = streams[0].Read(fileBuffer, totalBytesRead, fileBuffer.Length - totalBytesRead);
    totalBytesRead += bytesRead;
} while (bytesRead != 0);

Stream.Read вернет 0, когда не осталось данных для чтения.

Выполнение таких действий будет работать лучше, чем чтение байта за раз.Это также дает вам способ убедиться, что вы прочитали правильное количество байтов.Если totalBytesRead не равно числу байтов, которое вы ожидали после завершения цикла, то произошло что-то плохое.

0 голосов
/ 05 марта 2011

Спасибо за ваш вклад Tvanfosson. Я возился с моим кодом и сумел заставить его работать. Синхронность между моим клиентом и сервером была отключена. Я воспользовался вашим советом и заменил чтение на чтение байта по одному.

...