Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: качать файл больше чем в 1 сессию http  (Прочитано 14143 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Loki
Участник

ru
Offline Offline

« : 12-06-2008 13:28 » 

Как создать несколько потоков для скачивания 1 файла? Для этого нужно в каждом потоке запрашивать определенную часть файла  и расчитывать колличество частей или как?
Си!
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 13-06-2008 09:04 » 

А причём тут сессия и C++?  Частичные закачки поддерживаются на уровне HTTP или его рассширений типа WebDAV и, соответственно, веб-сервера. По-моему, там служебное слово RANGE используется.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Гость
« Ответ #2 : 13-06-2008 09:56 » 

Loki, смотри в сторону Url monikers: URLOpenStream и т. п.
Записан
Loki
Участник

ru
Offline Offline

« Ответ #3 : 13-06-2008 11:27 » 

Про range в курсе, только пока не в курсе как несколько потоков создать одновременных и при этом правильно их в один файл собрать. URLOpenStream не подойдет, мне под линукс нужно.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #4 : 13-06-2008 12:32 » 

Loki, А в чем проблема? Создать потоки? Смотри в сторону pthread_create или на крайний случай fork
Создаеш отдельный поток (поток "А"). В нем открываеш файл на запись. Все остальные потоки (которые будут качать с нета) будут просто скидывать в буффер в памяти данные с меткой на начало записи данных. Как только буффер заполнится, брать новый буффер для продолжения работы, заполненный буффер отдавать в поток "А". Как правило файл создается сразу с тем размером, который будет скачен. Теперь только в потоке "А" остается спозиционироваться на начало записи и записать (опустошить буффер) и отдать его на дальнейшее использование. Если нет работы, с помошью мьютексов поток "А" можно усыплять. Конечно надо будет подумать об дисперичизации скаченных фрагментов.
« Последнее редактирование: 13-06-2008 12:33 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 13-06-2008 15:43 » 

Loki, метод примерно такой:
1. Делаешь первый запрос без Range и в ответе получаешь размер файла в поле Content-Length. Теперь запрос можно: либо обрубить, а данные отбросить, либо продолжать считывать, но в цикле чтения из сокета добавляешь логику, ограничивающую длину считанного блока (см. п.2).
2. Вычисляешь, сколько будет потоков и сколько байт надо скачать каждому потоку.
3. Создаешь N запросов, каждый со своим значением Range.

Трудности, которые тебя ждут:
1. Поддержка Content-Encoding: gzip, chunked.
2. Обработка ответа сервера. Коды ответов: 200 - при полном файле, 206 - частичный файл, 30х - редиректы, 40х - запреты, авторизация, отсутствие файла, 50х - сбой на сервере, 10х - можно игнорировать, но может содержать полезную информацию.
3. Обязательно надо передавать в запросах параметры Host и User-Agent.

Подумай о библиотеке CURL.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Loki
Участник

ru
Offline Offline

« Ответ #6 : 14-06-2008 01:59 » 

подскажите что не так?
Вот что при сборке в с++
Код:
int main(int argc, char **argv){
..etc...
        if (argc != 2){
                fprintf(stderr, "Usage: %s <host name> \n", argv[0]);
                exit(1);
        }
        for(num_connect = 0; num_connect < 35; num_connect++){
//pthread.cc:34: ошибка: некорректное преобразование из 'void*' в 'void* (*)(void*)'
//pthread.cc:34: ошибка:   при инициализации 3 -го аргумента 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)'
                ret = pthread_create(&tid[num_connect], NULL, (void *)squirtIt, argv[1]);
        }
        for(num_connect = 0; num_connect < 35; num_connect++){
                pthread_join(tid[num_connect], NULL);
}
А при сборке в Си
/tmp/cc8MIS1o.o: In function `main':
pthread.c:(.text+0xa8): undefined reference to `pthread_create'
pthread.c:(.text+0xd5): undefined reference to `pthread_join'
collect2: выполнение ld завершилось с кодом возврата 1
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 14-06-2008 05:29 » 

Ты подключаеш библиотеку pthread при сборке через опцию -l ?
Напиши так ret = pthread_create(&tid[num_connect], NULL, &squirtIt, (void*)argv[1]); Сама функция squirtIt должна выглядеть так void *squirtIt(void * arg)
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Loki
Участник

ru
Offline Offline

« Ответ #8 : 14-06-2008 14:14 » 

сама функция у меня выглядит вот как
void *squirtIt(char *hName);
а аргументы задаются тут
int main(int argc, char **argv){
библиотеку подключаю обычно...
#include <pthread.h>
у меня вот как
Код:
//void *squirtIt(char *hName);
void *squirtIt(void * arg, char *hName) // только это похоже больше на с++, в сишном ломается.
char letsGetStarted[128];
int main(int argc, char **argv){
...........
        for(num_connect = 0; num_connect < 35; num_connect++){
        //      ret = pthread_create(&tid[num_connect], NULL, (void *)squirtIt, argv[1]);
                ret = pthread_create(&tid[num_connect], NULL, &squirtIt, (void*)argv[1]);
        }
        /* assuming any of these threads actually terminate, this waits for all of them */
        for(num_connect = 0; num_connect < 35; num_connect++){
                pthread_join(tid[num_connect], NULL);
        }
странно что деклараци слетели, строку я добавил в функцию
pthread.cc:20: ошибка: expected initializer before 'char'
pthread.cc: In function 'int main(int, char**)':
pthread.cc:25: ошибка: нет декларации 'letsGetStarted' в этой области видимости
pthread.cc:36: ошибка: нет декларации 'squirtIt' в этой области видимости
pthread.cc: In function 'void* squirtIt(char*)':
pthread.cc:65: ошибка: нет декларации 'letsGetStarted' в этой области видимости

Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #9 : 14-06-2008 16:54 » 

Loki, Читай RTFM по построению программ в С++/С. Ты пытаешся применять, не зная правил построения программ. Для начала выбери, а чем ты хочеш компилировать. В С или С++. Они вроде бы и одинаковые, но у них синтаксис чуть отличается.
Вот тут https://forum.shelek.ru/index.php/topic,9206.msg134063#msg134063 я приводил пример программы с применением потоков. В Частности функция самого потока void* icmpin(void *arg). Иницилизация происходит в функции main. Правда я там не передавал аргумент в поток. Компилировал бы я тот пример примерно бы с такой строкой g++ ping.cpp -lpthread -o ping -Wall.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Loki
Участник

ru
Offline Offline

« Ответ #10 : 16-06-2008 09:04 » 

нужно было собрать с опцией -lpthread
Записан
Loki
Участник

ru
Offline Offline

« Ответ #11 : 22-06-2008 14:30 » 

А как качать каждую часть файла используя другой исходный ip- адрес? Т.е. поток создать через ip хоста в той же подсети что и собственный хост. Только это не арп-спуф, просто юзать еще один адрес... или подесть.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 22-06-2008 14:51 » 

Loki, ты можешь использовать другие IP своего хоста. Для этого тебе придется, прежде чем делать connect(), сделать bind() на нужный адрес.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Loki
Участник

ru
Offline Offline

« Ответ #13 : 22-06-2008 14:59 » 

А если у меня только один адрес и локалхост, то ничего не выйдет?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 22-06-2008 15:06 » new

Loki, совершенно верно.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines