Russian Qt Forum

Qt => Работа с сетью => Тема начата: fuCtor от Февраль 24, 2009, 16:39



Название: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Февраль 24, 2009, 16:39
на днях появилась идея сделать небольшую утилитку для мониторинга и управления rTorrent-ом. Нашел библиотеку(код) реализации XML-RPC клиента: http://code.google.com/p/qxmlrpc/
Данный клиент работает в асинхронном режиме. Поэтому сделал обертку над всеми методами и тд. В итоге получилось что каждый класс по таймеру (у каждого свой таймер) запрашивает обновления о состояниях, и обновляет внутренние переменные. Вот тут и возникла проблема. При наличии в списке большого количества торентов отправляется большое количество запросов, примерно 8-9 на каждый. В результате чего процессор загружается до 60% на некоторое время. Для приложения это не заметно т.к. весь этот процесс вынесен в отдельный поток.

Как можно оптимизировать данную задачу? Пока решил тем что увеличил интервал обновления данных.
А также любая конструктивная критика приветствуется =).

Исходники прилагаются.

UPD: обнаружил утечку памяти... приличную утечку  :-\... но еще не устранил :(...
UPD2:
Утечку нашел в файле xmlrpc/client.cpp:167
QBuffer *outBuffer = new QBuffer;

Только как исправить :(


Название: Re: XML-RPC клиент для rTorrent
Отправлено: vaprele07 от Февраль 25, 2009, 03:49
QBuffer *outBuffer = new QBuffer(this);


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Февраль 25, 2009, 08:11
Так вроде тогда объект удалится когда удалится и родитель. Но родитель (xmlrpc::Client) создается при запуске и удаляется после закрытия, а в промежутке между этим объекты все равно будут копиться, или я что-то не до понял в механизмах Qt?


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 09:27
1. или вместо
Код:
    QBuffer *outBuffer = new QBuffer;

написать :
Код:
    QBuffer outBuffer;

2. или после
Код:
    d->serverResponses[id] = outBuffer;
написать:
Код:
delete(outBuffer);
outBuffer = 0;

не?


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Февраль 25, 2009, 09:34
непонятно зачем вот это?
Код:
delete(outBuffer);
outBuffer = 0;

если вы выше объект в стеке создаете.
Код:
QBuffer outBuffer;


Название: Re: XML-RPC клиент для rTorrent
Отправлено: BRE от Февраль 25, 2009, 09:40
не?
Не.

Камрады, посмотрите весь код. Этот буфер используется в requestFinished. Вот там и нужно его освобождать.
Внимание обращаем на те места где используется d->serverResponses.take(id)

P.S. Да, это только беглый взгляд на этот код, возможны недосмотры.  :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: vaprele07 от Февраль 25, 2009, 10:22
может стоит QByteArray хранить вместо буфера?


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 10:26
2 spirit  , внимательнее надо быть ! :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Февраль 25, 2009, 12:45
Вот итоговый слот, утечки нет наконец-то =)
Код
C++ (Qt)
void Client::requestFinished(int id, bool error)
{
   if ( !d->serverResponses.count(id) ) {
       return;
   }
 
#ifdef XMLRPC_DEBUG
   qDebug() << "request" <<  d->methodNames[id] <<  "finished, id=" << id << ", isError:" << error;
#endif
 
   if ( error ) {
       //if ( d->serverResponses.count(id) )
 
       delete d->serverResponses.take(id);
 
       emit failed(id, -32300, d->http->errorString() );
       return;
   }
 
   if ( d->serverResponses.count(id) ) {
QBuffer * inBuffer = d->serverResponses.take(id);
       QByteArray buf = inBuffer->buffer();
 
       //qDebug() << "xml-rpc server response:\n" << QString(buf);
 
       Response response;
 
       QString errorMessage;
       if ( response.setContent( buf, &errorMessage ) ) {
           Q_ASSERT( !response.isNull() );
 
           if ( response.isFault() ) {
               qDebug() << "request failed:" << response.faultCode() << response.faultString();
               emit failed(id, response.faultCode(), response.faultString() );
           } else {
#ifdef XMLRPC_DEBUG
               qDebug() << response.returnValue().pprint();
#endif
               emit done( id, response.returnValue() );
           }
 
       } else {
 
#ifdef XMLRPC_DEBUG
           qDebug() << "incorrect xmlrpc response:" << errorMessage;
           qDebug() << QString(buf);
#endif
           emit failed(id, -32600, "Server error: Invalid xml-rpc. \nNot conforming to spec.");
       }
delete inBuffer;
   }
 
}
Надо будет автору кода отправить изменения.

А основная часть вопроса остается актуальной, можно ли как-нибудь оптимизировать обновление данных?
UPD: поправил при случаи ошибки.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: Rcus от Февраль 25, 2009, 13:01
Все же есть. если произойдет ошибка то буфер не удалится


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 14:11
Так нужно или не нужно писать патч?

ЗЫ: мне эта билиотека тоже оч нужна будет! Поэтому и интересуюсь! :)

ЗЫЗЫ: киньте кто- нить на почту scapig@yandex.ru и на scapig2040@rambler.ru архив с этой библой, т.к у нас на работе админ палит то что кто качает... да и скачать из Windows не имея svn не хочется (по одному файлу) :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Февраль 25, 2009, 14:13
имхо, нужно, а то как-то с утечкой несерьезно  ;)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 14:16
Ну так исправленную версию и скиньте мне на почту пожалуйста! :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Февраль 25, 2009, 14:24
Отправил, смотрите почту.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 14:36
не, ничего нету... сдублируйте если не трудно и на :  scapig2040@rambler.ru

PS: злостный админ фильтрует :(


Название: Re: XML-RPC клиент для rTorrent
Отправлено: kuzulis от Февраль 25, 2009, 16:49
Все, принял! Спасибки! :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Февраль 28, 2009, 19:06
"Мы строили строили и наконец построили" (с)

Вот что вышло:
(http://ajieks.org.ru/uploads/rwin.jpg)

Исходники пока не выкладываю, еще относительно сырая программа.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: ритт от Март 01, 2009, 18:21
ничО так, симпатишно.
ждём релиза


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 02, 2009, 20:00
Вот тут исходники можно взять :)
http://ajieks.org.ru/index.php?post=470


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Март 02, 2009, 20:09
delete_completed нигде не определен. что-то с уишкой видать.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Март 02, 2009, 20:14
еще краш при выходе нашел.
мессага в аттаче.
(http://crash.png)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 02, 2009, 20:58
delete_completed странно, ничего подобноо не писал... завтра гляну..

А краш так понял судя по сообщению возникает из-за того что сокет куда то пытается слать сообщения а приемника нет?
Отлаживал в студии 2008, там не было никаких сообщений, только код завершения 13A, но что значит не нашел.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Март 02, 2009, 20:59
я собирал студией.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 03, 2009, 15:54
Пытаюсь на выходе словить этот эксепшн. Не ловится :( прям мистика.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Март 03, 2009, 16:07
в дебаге ловишь? могу видео записать.  :)


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 03, 2009, 16:16
А если вот такие изменения внести в rtorrentio.cpp:
Код
C++ (Qt)
RTorrentIO::~RTorrentIO()
{
if(!--InstanceCount)
{
//terminate ();
quit();
//delete client;
}
}
 
Client * RTorrentIO::operator ->()
{
return client;
}
 
void RTorrentIO::run(){
if(InstanceCount == 1)
{
client = new Client(parent());
client->setHost(hostname,port,path);
}
exec();
delete client; //возможно лишнее т.к. точка останова сюда не попадала ни разу.
}
 

Будет вываливаться?


Название: Re: XML-RPC клиент для rTorrent
Отправлено: spirit от Март 03, 2009, 16:21
ага, перестало валиться.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: pastor от Март 03, 2009, 16:22
Цитировать
The child of a QObject must always be created in the thread where the parent was created.
You must ensure that all objects created in a thread are deleted before you delete the QThread.
This can be done easily by creating the objects on the stack in your run() implementation.

Ваш код:

Код
C++ (Qt)
void RTorrentIO::run(){
...
   client = new Client(parent());
...
   exec();
   delete client;
   client = 0;
}

Уберите parent().


Цитировать
delete client; //возможно лишнее т.к. точка останова сюда не попадала ни разу.

а вот это какраз и не лишнее. Этот код должен выполнится после завершения exec (завершение потока). Лишнее было в деструкторе. Перепешите его так:

Код
C++ (Qt)
RTorrentIO::~RTorrentIO()
{
if(!--InstanceCount)
{
quit();
wait();
}
}

Также настараживает вот этот код:

Код
C++ (Qt)
Client * RTorrentIO::operator ->()
{
return client;
}

и более того - InstanceCount. Т.е. экземпляр Client создается для пераого потока и используется для остальных??? Тут налицо неправильная работа с потоком


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 03, 2009, 16:27
ага, перестало валиться.

Цитировать
The child of a QObject must always be created in the thread where the parent was created.

Ваш код:

Код
C++ (Qt)
void RTorrentIO::run(){
...
   client = new Client(parent());
...
}

Ага спасибо, разобрался, конструктор в одном потоке был, а деструктор в другом. На ошибках учатся.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: pastor от Март 03, 2009, 16:37
2 fuCtor: выложи полный код RTorrentIO


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 03, 2009, 16:49
Вот, с внесенными изменениями:
http://code.google.com/p/rwin/source/browse/trunk/src/rtorrent/rtorrentio.cpp


Название: Re: XML-RPC клиент для rTorrent
Отправлено: ритт от Март 03, 2009, 23:17
вай-вай...краш при попытке соединиться...

кстати, /RPC2 на сервере откуда должно взяться? у меня рторрент 0.6.4 и накакой вэб-части у него не вижу. /* сильно не пинайте - я с торрентами ещё на "вы" */


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 04, 2009, 07:47
http://www.permlug.org/node/3941/ вот тут инструкция о настройке xml-rpc для rtorrent-а
Сам он работает через scgi интерфейс, а если прикрутить сервер то будет как положено.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: pastor от Март 04, 2009, 12:39
2  fuCtor, посомрел код, нужно сделать небольшие правки:

Код
C++ (Qt)
void RTorrentIO::run(){
       if(InstanceCount == 1)
       {
               client = new Client();
               client->setHost(hostname,port,path);
       }
       exec();
 
       if(!InstanceCount) { //удалеям когда нет ниодного экземпляра потока
           delete client;
           client = 0;
       }
}

Но чесно сказать смонительная реализация RTorrentIO. Меня настараживает использование статического члена
Цитировать
client
. Создается в одном потоке, может быть удален в другом.

Доступ к client никак не защищен:

Код
C++ (Qt)
Client * RTorrentIO::operator ->()
{
       return client;
}

что будет при попытке одновременной модификации данных client? Правильно, ничего хорошего

Также непонятные дейтвия в конструкторе:

Код
C++ (Qt)
....
if(!InstanceCount)
{
   start();
}else
{
   quit();
}
InstanceCount++;
....

Если на то дело пошло, то тогда так:

Код
C++ (Qt)
....
if(!InstanceCount)
{
   start();
}else
{
   quit();
   wait();
}
InstanceCount++;
....

Хотя смысла я непонимаю в этом коде.

Диструктор тоже нужно изменить для корректного завершения потока, примерно так:

Код
C++ (Qt)
RTorrentIO::~RTorrentIO()
{
   if (isRunning()) {
       quit();
       wait();
   }
}

Так что незнаю что вам подсказать, т.к. незнаю что должно быть.


Название: Re: XML-RPC клиент для rTorrent
Отправлено: fuCtor от Март 04, 2009, 15:12
Идея была в том, чтобы создать один экземпляр потока, в котором будет крутиться соответственно единственный Xml-Rpc клиент. Связь с другими потоками через сигналы. При первом создании указывается настройки для доступа, а в остальных классах просто получаю доступ к уже имеющемуся экземпляру. Когда количество экземпляров будет 0 то уничтожить и client. Вот как-то так. Вот только интересно, будет ли работать обмен быстрее, если каждый класс будет владеть своим экземпляром Сlient  ???
 
На счет конструктора согласен :).



Название: Re: XML-RPC клиент для rTorrent
Отправлено: pastor от Март 04, 2009, 15:31
Вот только интересно, будет ли работать обмен быстрее, если каждый класс будет владеть своим экземпляром Сlient  ???

Попробкйте, т.к. текущая реализация неверна, имхо.


На счет конструктора согласен :).

Более того, я бы сказал, что потоки все после первого (с InstanceCount >1) будут совершено бесполезны, т.к. они будут незапущены. start() вызывается только для первого потока.