Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие _ использование QNetworkAccessManager

Автор: eldar85 11.8.2010, 10:58

пробую сделать класс для работы на QNetworkAccessManager но нифига не пойму одного, вот сделал такой код:

net.h

#ifndef NET_H
#define NET_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include "QtGui"

class network : public QObject
{
Q_OBJECT

public:


network *load(QString url);
network *setRef(QString ref);
network *setPost(QByteArray post);
QString exec();


private:
QString referer;
QString buffer;




QNetworkAccessManager manager;
QNetworkReply *reply;
QString Url;
QUrl apiUrl;
QByteArray postdata;




public slots:
void getReplyFinished();
void readyReadReply();


};



#endif // NET_H


net.cpp

#include "net.h"




network *network::load(QString newUrl)
{
Url = newUrl;
qDebug() << "1 ";
return this;
}

network *network::setRef(QString ref)
{
referer = ref;
return this;
}

network *network::setPost(QByteArray post)
{
postdata = post;
qDebug() << "2";
return this;
}

QString network::exec()
{


// apiUrl = "http://www.forismatic.com/api/1.0/";
//postdata = "method=getQuote&format=xml";
if(postdata != "")
{
QNetworkRequest request;
request.setUrl(QUrl(Url));
reply = manager.post(request, postdata);


connect(reply, SIGNAL(finished()), this, SLOT(getReplyFinished()));
connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadReply()));

}

qDebug() << buffer;
return buffer;
}

void network::getReplyFinished()
{
reply->deleteLater();

}

void network::readyReadReply()
{
buffer = QString::fromUtf8(reply->readAll());




}


ну и сам вызов в главном классе

network *net = new network;


QString xStr = net->load("http://www.forismatic.com/api/1.0/")->setPost("method=getQuote&format=xml")->exec();



qDebug() << xStr;


по идее exec() должен вернуть buffer с данными, он он гад ничего не возращает, причем в слоте

void network::readyReadReply()
{
buffer = QString::fromUtf8(reply->readAll());

}


загрузка производится, но exec() завершается до того как произойдет вывод reply в buffer. В чем же проблема???

Автор: Алексей1153 11.8.2010, 11:19

много недосказано :)

Цитата(eldar85 @ 11.8.2010, 13:58) *
по идее exec() должен вернуть buffer с данными

и присвоить его QString ? А что за буфер, кстати


Цитата(eldar85 @ 11.8.2010, 13:58) *
net->load(...)->setPost(...)->exec();

проверял ли, каждый элемент цепочки вызовов возвращает корректные объекты ?

Автор: eldar85 11.8.2010, 11:55

ну exec() возвращает QString, а buffer это QString, он объявляется в net.h
да все работает, единственное что именно exec() завершается и только потом срабатывает слот

void network::readyReadReply()
{
buffer = QString::fromUtf8(reply->readAll());

}


в нем уже есть ответ от сервера, а мне нужно чтобы этот ответ произошел до завершения exec(), чтобы exec() вернул buffer в месте вызова.

в слоте
void network::readyReadReply()
{
buffer = QString::fromUtf8(reply->readAll());
qDebug() << buffer; //получается ответ сервера,но он получается после завершения exec(), а мне нужно чтобы exec() возвращал buffer с ответом сервера

}

Автор: Алексей1153 11.8.2010, 11:56

Насколько я понимаю, когда происходит выход из exec, объект уже завершил работу

А это значит, что тебе в network::readyReadReply() нужно отправить сигнал с буфером в объект основного класса

Автор: eldar85 11.8.2010, 12:04

net->load(...)->setPost(...)->exec();
а тут все нормально срабатывает, да проверял, и load() доставляет что нужно и setPost() и exec() принемает все как нужно, единственное он завершается до того как вызовится слот network::readyReadReply() который присвоит QString buffer ответ сервера...

из exec() выход происходит до того как был получен ответ от сервера в network::readyReadReply(), получается в функции основного класса

void MainWindow::start()
{




    network *net = new network;


  
    QString xStr =  net->load("http://www.forismatic.com/api/1.0/")->setPost("method=getQuote&format=xml")->exec();


    
    qDebug() << xStr;

}


уже заканчивается и только потом происходит ответ от сервера.

а мне нужно в start() сделать несколько вызовов и еще парсить и вырезать лишнее в ответе сервера

Автор: Алексей1153 11.8.2010, 12:07

так тебе асинхронно надо работать. После запуска нужно дождаться сигнала о приходе данных данных, только потом их считать. В структуре твоего кода не копался, сорри, некогда

Автор: eldar85 11.8.2010, 12:13

а так получается что в start() был сделан вызов load(), setPost(), exec(), они сработали и завершились, потом завершился старт и только потом вызвался слот network::readyReadReply() который вернул ответ сервера...

да я понимаю что асинхронно нужно но вот никак не пойму как это сделать((

Автор: Алексей1153 11.8.2010, 12:29

eldar85, для асинхронного обмена объект должен жить дольше времени работы с ним. У тебя это выполняется?

Например, объект должен быть членом основного класса

Цитата
ну и сам вызов в главном классе

network *net = new network;
QString xStr = net->load("http://www.forismatic.com/api/1.0/")->setPost("method=getQuote&format=xml")->exec();
qDebug() << xStr;


здесь код должен быть разделён по меньшей мере на 3 части:

1)
процедура создания объекта для асинхронной работы (это может быть и в конструкторе главного класса)
CMainClass::CMainClass(...):...
{
    ...
    network *net = new network;
    ...
}


2) процедура запроса данных
CMainClass::RequestNewData(......)
{
  net->load("http://www.forismatic.com/api/1.0/");
  net->setPost("method=getQuote&format=xml");
  net->exec();
}


3) слот приёма данных
CMainClass::slot_GotNewData(const QString& data)
{
   qDebug() << data;
}

Автор: eldar85 11.8.2010, 12:41

как же я тогда получу ответ вот сдесь

CMainClass::RequestNewData(......)
{
  net->load("http://www.forismatic.com/api/1.0/");
  net->setPost("method=getQuote&format=xml");
  net->exec();
}


и смогу в этой же функции парсить ответ сервера и делать еще несколько пост запросов с выпарсинными данными из первого запроса?

Автор: Алексей1153 11.8.2010, 13:11

ну дык... как то так:

void network::readyReadReply()
{
    buffer = QString::fromUtf8(reply->readAll());
    emit pMainClassObj->slot_GotNewData(buffer);
}


А для составления требуемого порядка - завести ассоциативный упорядоченный список по времени посылки сообщения
atd::map<время,QString> m_RequestList;

, а так же список для принимаемых сообщений (если надо)
А дальше - логика

Автор: eldar85 11.8.2010, 13:24

да такое я пробывал

void network::readyReadReply()
{
    buffer = QString::fromUtf8(reply->readAll());
    emit pMainClassObj->slot_GotNewData(buffer);
}

не помогает...

а про atd::map<время,QString> m_RequestList; я не понял, как это?

Автор: Алексей1153 11.8.2010, 13:33

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

блин, там std, а не atd

Автор: eldar85 11.8.2010, 14:18

как все неудобно(( я думал перейтис cUrl на Qt шные методы работы с сетью будет удобнее, но оказалось все вообще стремно в библиотеке QNetwork либо просто по другому как то делать нужно...
по идее я хотел чтобы я мог в главном методе start() вызвать к примеру загрузку одной страницы, затем в этом же старте получив ответ от сервера в строку получить нужные данные тут же start() отправить пост запрос с полученными данными от первой загрузки и так далее... но получается одна ерунда, единственное что получилось вызвать в главном методе загрузку страницы с сервера и слотом поместить ее в переменную но только после того как произведен выход из start() и exec(). а мне нужно чтобы в start() вызвалось exec() затем дождалось окончания загрузки, получило ответ от exec() и только потом тут же в start() начало действие дальше как в обычном с++ когда вызываешь из одной функции другую функцию то первая не завершает работу пока функция вызванная внутри нее не завершит работу...

Автор: BRE 11.8.2010, 14:27

Ты про синхронную загрузка?
На форуме были темы в которых этот способ обсуждался. Поищи.
Посмотри на класс QEventLoop.

Автор: eldar85 11.8.2010, 15:48

решил задачу с помощью простого цикла))))

QString network::exec()
{
    
    
    manager = new QNetworkAccessManager;
    QNetworkRequest request;
    request.setUrl(QUrl(Url));
    reply = manager->post(request, postdata);
    
    
    
    connect(reply, SIGNAL(finished()), this, SLOT(getReplyFinished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadReply()));
    
    while(buffer == "")
    {
        qApp->processEvents();
    }
    
    
    return buffer;
    
}

Автор: Алексей1153 11.8.2010, 16:46

eldar85, не во всякой задаче удасться так сделать :)

Ну а в твоём решении ещё не помешало бы таймаутом задаться, а то навсегда может зависнуть

Автор: eldar85 11.8.2010, 17:28

да я подкоректировал немного с таймаутом...

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)