Russian Qt Forum

Qt => Работа с сетью => Тема начата: ecspertiza от Июль 02, 2010, 10:25



Название: QNetworkAccessManager и тишина после get()
Отправлено: ecspertiza от Июль 02, 2010, 10:25
Как то давно пытался реализовать на Qt удобное API для многопоточной закачки файлов по Http и Ftp, но как то со временем был кисляк, и сейчас опять взялся, в общем наткнулся на магию, после вызова метода get() класса QNetworkAccessManager полная тишина, ни один слот не вызывается, вот решил выложит код на суд гуру, конечно понимаю что сам где то накосячил, но что то не могу найти где. 

метод get() расположен в файлике http_download.cpp
Код:
void HttpDownloadSection::run()
{
    qDebug() << "Start thread download section";

    QNetworkRequest request;
    request.setUrl(download_url);

    manager = new QNetworkAccessManager(0);
    manager->moveToThread(this);
    connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finished(QNetworkReply*)));

    reply = manager->get(QNetworkRequest(QUrl(download_url)));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadProgress(qint64,qint64)));
    connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(errorDonload(QNetworkReply::NetworkError)));

    exec();
}


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ufna от Июль 02, 2010, 11:10
а как тестировать то прогу? В смысле какие агрументы?

больше всего похоже что мэнеджер и реплай - в разных потоках. Самое рабочее решение здесь отослать сигнал какой-нибудь, связанный со слотом, который начнет загрузку, а потом делать exec() - тогда все будет точно в одном потоке дальше, а то "до exec()" и "после exec()" - воспринимается разными потоками для этой хрени, я тут вчера имелся с многопоточной загрузкой на сервак как раз.


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ecspertiza от Июль 02, 2010, 11:13
а как тестировать то прогу? В смысле какие агрументы?

Первый аргумент это url на файл а второй кол-во потоков

больше всего похоже что мэнеджер и реплай - в разных потоках. Самое рабочее решение здесь отослать сигнал какой-нибудь, связанный со слотом, который начнет загрузку, а потом делать exec() - тогда все будет точно в одном потоке дальше, а то "до exec()" и "после exec()" - воспринимается разными потоками для этой хрени, я тут вчера имелся с многопоточной загрузкой на сервак как раз.

вполне может быть, но даже если сделать просто
Код:
manager->get(QNetworkRequest(QUrl(download_url)));

то хотя бы finished должен был бы вызвать ???


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ufna от Июль 02, 2010, 11:33
Ну ты и намудрил с потоками, я тебе скажу.

Ошибка у тебя в том, что "части" ты создаешь в потоке "загрузка", и туда их тыкаешь, а поток "загрузка" у тебя в эвент луп не входит. Добавь exec() в HttpDownload::run() и данный пункт у тебя радостно заработает.


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ecspertiza от Июль 02, 2010, 11:38
И то верно, перемудрил, спасибо заработало, как то упустил :)


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: SimpleSunny от Июль 02, 2010, 12:02
ТАм не только с потоками перемудрено :)
Немного покритикую.

Что это за дивная контрукция?
Код
C++ (Qt)
int index = 0;
   for (index ; index < storage.size();)
   {
       if (storage[index].url == handle.url)
       {
           storage[index] = handle;
           break;
       } ++index;
 
       if (storage[index].url == handle.url)
       {
           storage[index] = handle;
           break;
       } ++index;
 
       if (storage[index].url == handle.url)
       {
           storage[index] = handle;
           break;
       } ++index;
 
       if (storage[index].url == handle.url)
       {
           storage[index] = handle;
           break;
       } ++index;
   }
 
Возможно подразумевалось такое?
Код
C++ (Qt)
int index;
   for (index = 0; index < storage.size(); ++index)
   {
       if (storage[index].url == handle.url)
       {
           storage[index] = handle;
           break;
       }
   }
 

Код
C++ (Qt)
if (storage[index].status != HandleFile::Error)
Следовало бы сделать проверку на коректность index (index < storage.size()).

Код
C++ (Qt)
           if ((i+1)*h_file.length > h_file.length)
           {
               listDownloadSection.append(new HttpDownloadSection(h_file.url,i*(h_file.length / h_file.count_thread ),
                                                                  h_file.length,h_file.accept_range,0));
               listDownloadSection[listDownloadSection.count()-1]->moveToThread(this);
               listDownloadSection[listDownloadSection.count()-1]->start();
           }
           else
           {
               listDownloadSection.append(new HttpDownloadSection(h_file.url,i*(h_file.length / h_file.count_thread ),
                                                              (i+1)*(h_file.length / h_file.count_thread ),h_file.accept_range,0));
               listDownloadSection[listDownloadSection.count()-1]->moveToThread(this);
               listDownloadSection[listDownloadSection.count()-1]->start();
           }
       }
 

Было б понятней, если бы выглядело так:
Код
C++ (Qt)
int size;
if ((i+1)*h_file.length > h_file.length)
   size = h_file.length;
else
   size = (i+1)*(h_file.length / h_file.count_thread );
 
listDownloadSection.append(new HttpDownloadSection(h_file.url,i*(h_file.length / h_file.count_thread ), size ,h_file.accept_range,0));
listDownloadSection.last()->moveToThread(this);
listDownloadSection.last()->start();


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ecspertiza от Июль 02, 2010, 12:17
Немного покритикую.

Это всегда пожалуйста, критика это хорошо :)

Что это за дивная контрукция?

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

Следовало бы сделать проверку на коректность index (index < storage.size()).

возможно, но я не могу представить себе ситуацию когда index будет больше чем storage.size() ибо при инициализации  он равен нулю, а в цикле заданно
Код:
index < storage.size()

и index используется только внутри этой ф-ции, это же не глобальная переменная

Было б понятней, если бы выглядело так:

с этим согласен, действительно было бы понятнее :)


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: SimpleSunny от Июль 02, 2010, 13:26
если я не ошибаюсь, такой поиск осуществляется  в контейнерах stl , ибо сама по себе одна итерация for это довольно долгая операция ,а сравнение работает гораздо быстрее , то в этом случае поиск будет проходить быстрее, этот код поиска я чуть позже вынесу в отдельную ф-цию и буду передавать возвращаемое значение по ссылке.
Преждевременная оптимизация - зло :)
Такой подход был бы оправдан, если бы количество итераций было бы задано заранее и это место было бы узким в роботе программы. А так получаем плохо читаемый код к тому же с ошибкой, так как нет гарантий, что где-то в середине тела цикла index не превысит storage.size() - 1.
К тому же компиляторы и сами хорошо умеют частино разворачивать циклы для повышения бытсродействия.
В контейнерах stl используются итераторы и конструкции наподобии такого
Код
C++ (Qt)
while (__first != __last && !(*__first == __val))
   ++__first;
return __first;

возможно, но я не могу представить себе ситуацию когда index будет больше чем storage.size() ибо при инициализации  он равен нулю, а в цикле заданно
Код:
index < storage.size()
и index используется только внутри этой ф-ции, это же не глобальная переменная
Когда поиск не увенчался успехом. index=storage.size();


Название: Re: QNetworkAccessManager и тишина после get()
Отправлено: ecspertiza от Июль 02, 2010, 13:31
Преждевременная оптимизация - зло
Такой подход был бы оправдан, если бы количество итераций было бы задано заранее и это место было бы узким в роботе программы. А так получаем плохо читаемый код к тому же с ошибкой, так как нет гарантий, что где-то в середине тела цикла index не превысит storage.size() - 1.
К тому же компиляторы и сами хорошо умеют частино разворачивать циклы для повышения бытсродействия.

согласен, пожалуй поправлю :)

Когда поиск не увенчался успехом. index=storage.size();

Про это уже подумал, и добавил проверку :)

Если будет еще критика, то пишите, критика тем более здравая на мой взгляд никогда лишней не бывает :)

P.S. Убивает как на этом движке реализована кнопка "Цитата"  :)