Передача файлов через сокеты, окончательный размер с меньшим количеством байтов

StackOverflow https://stackoverflow.com/questions/684733

  •  22-08-2019
  •  | 
  •  

Вопрос

Я пытаюсь получить файл через сокеты в C.Но сервер отправляет мне, например, 64-байтовые пакеты для файла размером 1000000 байт, и я получаю примерно 999902 байта в файле назначения.

while ((n = read(sd, buffer_in, BUFSIZE ))) //  BUFSIZE = 64 
{
    if(n<0)
    {
       printf("Fail.\n");
       fclose(archivo);
       return -1;
    }

    if(fwrite(buffer_in, n, 1, f) !=1 ) 
    { 
       printf("fwrite error.\n");
       fclose(archivo);
       return -1;
    }

    bytes+=n;
}

printf("We received %d bytes",  bytes);

При использовании через локальный сокет TCP/IP он работает, но не при медленном соединении.В ходе отладки я вижу, что получаю много 64-байтовых фрагментов и 30-байтовый фрагмент рядом с EOF.Я знаю, что вы можете получить меньше байтов при read(), поскольку вызов возвращается, когда доступны какие-либо данные (> 1 байт).Но это условие не должно быть уловлено вовремя?Должен вернуться, когда n == 0, то есть больше нет данных (EOF).

Спасибо за вашу помощь.

(РЕДАКТИРОВАТЬ)

Отправка кода следующим образом:

while (n=read(file_fd, buffer, BUFSIZE))
{
   write (sdaccept, buffer, n)
}

Я знаю, что и read(), и write() могут возвращать N < BUFSIZE, но разве этот цикл не должен обрабатывать это соответствующим образом?Я суммировал и возвращает 1000000, точный размер.

(РЕДАКТИРОВАТЬ II)

Протестировано с исходным кодом C с 10673 байтами, получает 10575 без повреждений, за исключением того, что в целевом файле НЕТ первых 98 байтов!!!

Это было полезно?

Решение

Предоставленный код отправки игнорирует тот факт, что write() (или send()) в сокете не обязан записывать весь буфер.

write()/send() может решить записать его частично или не записывать вообще, если базовая подсистема отказывается получать больше данных (например, сетевая подсистема может иметь очередь для отправки данных, и эта очередь уже заполнена).Это весьма вероятно при медленном соединении.

Отправляющая сторона должна проверить возвращаемое значение write(), чтобы определить, сколько данных было фактически записано, и соответствующим образом скорректировать его.

Запись должна быть сделана как-то так:

int readAmount;
while( readAmount = read(file_fd, buffer, BUFSIZE) > 0 )
{
    int totalWritten = 0;
    do {
       int actualWritten;
       actualWritten = write (sdaccept, buffer + totalWritten, readAmount - totalWritten);
       if( actualWritten == - 1 ) {
           //some error occured - quit;
       }
       totalWritten += actualWritten;
    } while( totalWritten < readAmount );
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top