Отправить файл в сокет - PullRequest
       18

Отправить файл в сокет

2 голосов
/ 29 января 2010

Я пытаюсь отправить файл в определенный сокет, используя C; вот код:

int send_file(char *filepath,int sock)
{
    FILE *fp=fopen(filepath,"rb");
    void *buff=malloc(2000);
    int i=1;
    while(i)
    {
        int bytes_read=fread(buff,1,2000,fp);
        i=!(feof(fp));
        int bytes_sent=0;
        while(bytes_sent<bytes_read)
        {
            int n=send(sock,buff+bytes_sent,bytes_read-bytes_sent,0);
            if(n==-1)
                return -1; //failure
            bytes_sent+=n;
        }

    }
    fclose(fp);
    free(buff);
    return 0;
}

Когда я запускаю эту программу и пытаюсь просмотреть текстовый файл в Firefox со значением http://127.0.0.1:8080/, часть файла обрезается с конца, если размер файла превышает 2000 байтов. Если я отправляю картинку, загружается только 3/4 картинки (обрезается снизу).

Функция всегда возвращает 0 вызывающей стороне. Куда исчезает последний кусок байтов, которые он отправляет ()? Нужно ли сбрасывать поток перед возвратом?

Спасибо

EDIT: Это фрагмент моей функции main ():

 send_file(filepath, sock);
 close(sock);
 return 0;
 }

Ответы [ 6 ]

1 голос
/ 29 января 2010

Вы никогда не должны использовать feof (), это почти всегда неправильно. Вместо этого используйте возвращаемое значение fread (), чтобы определить, когда вы прочитали все - если оно ненулевое, вам нужно продолжать чтение и отправку. В псевдокоде:

while(1) {
   r = fread( ... );
   if ( r == 0 ) {
      break;
   }
   send( .. );
}
1 голос
/ 29 января 2010

Для этого есть стандартный API! Используйте sendfile().

Ядро выполняет копирование без переключения контекста в ваш поток, что существенно более эффективно.

0 голосов
/ 30 января 2010

читаете ли вы все данные, отправленные вам веб-браузером? Если это не так (что понятно, если вы на самом деле не пишете веб-сервер), то вызов close() с непрочитанными данными вызывает прерывание соединения TCP вместо чистого отключения.

Чистое отключение ожидает отправки всех ожидающих данных; прерывание не выполняется, что может привести к потере этих данных.

В целях тестирования вы должны быть в состоянии исправить это, вставив это в конце функции отправки (перед тем как освободить buff):

shutdown(sock, SHUT_WR);    /* Send EOF to web browser */
while (recv(sock, buff, 2000, 0) > 0)
    ;  /* Read and discard until we see the browser's EOF (or an error) */
0 голосов
/ 30 января 2010

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

Я просто догадываюсь, но, скорее всего, в заголовке вы отправляете размер данных в 2000 байтов. Таким образом, даже если вы отправляете более 2000 байтов, браузер не ожидает их и отображает только первые 2000 байтов.

Кроме того, поскольку вы закрываете соединение, вы должны отправить Connection: close заголовок клиентам.

0 голосов
/ 29 января 2010

Код, который вы разместили, выглядит хорошо для меня. Как сказал Нил, проблема feof может существовать, хотя она прекрасно работает с использованием компилятора Microsoft. Я проверил это как написано с заглушкой для отправки вызова, и все данные были «отправлены». Мне кажется, что ошибка, возможно, лежит на принимающей стороне. Простым тестом было бы просто напечатать длины файлов, которые вы отправляете и читаете на обоих концах. Убедитесь, что вызов recv получает все сброшенные данные.

0 голосов
/ 29 января 2010

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

Если ваша программа завершает работу до того, как сокет завершит отправку своих данных, ОС не обязана что-либо делать с оставшимися неотправленными данными и, вероятно, выбросит их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...