Передача файлов через сокеты, конечный размер с меньшим количеством байтов - PullRequest
6 голосов
/ 26 марта 2009

Я пытаюсь получить какой-то файл через сокеты в 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).

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

(EDIT)

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

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

Я знаю, что read () и write () могут возвращать N

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

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

1 Ответ

11 голосов
/ 26 марта 2009

Предоставленный код отправки игнорирует тот факт, что 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 );
}
...