Russian Qt Forum
Май 17, 2024, 19:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QNetworkAccessManager и параметр Nonce [РЕШЕНО]  (Прочитано 13391 раз)
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« : Июль 04, 2013, 00:51 »

Есть у меня программа Qt Bitcoin Trader.
Решил наконец то перейти с QHttp на QNetworkAccessManager.
Но закрались подводные камни с параметром nonce.
Все запросы должны доходить до сервера в той последовательности что были отправлены.
В QHttp это работало как надо. Но не хватало возможности задать таймаут запроса и тп.

QNetworkAccessManager работает в параллельном режиме в 6 потоков.
Можно ли задать ему только 1 поток?

В сервер надо посылать число с постоянным инкрементом.
1,2,3,4, если придет 1,2,4,3 то будет ошибка.
« Последнее редактирование: Июль 09, 2013, 19:41 от IGHOR » Записан
thechicho
Гость
« Ответ #1 : Июль 04, 2013, 07:28 »

я такой код использую.
если поможет и как-то оптимизируете код, выложите тут свой вариант.

Код
C++ (Qt)
void Thread::GET(QNetworkAccessManager &qnam, int howReadAnswer, int headers, int redirect, QByteArray contentType, bool repeat)
{
   QEventLoop loopGet;
   int badProxyCount=0;
 
   request.setRawHeader("Content-Type", contentType);
 
   REPEATGET:
 
   reply = qnam.get(request);
   reply->ignoreSslErrors();
   //if (proxyType == "NoUseProxy")
//    QTimer timer;
//    timer.start(30000);
//    connect(&timer, SIGNAL(timeout()), &loopGet, SLOT(quit()));
 
   QTimer::singleShot(60000, &loopGet, SLOT(quit()));
   connect(reply, SIGNAL(finished()), &loopGet, SLOT(quit()));
   loopGet.exec();
 
   //if (proxyType == "NoUseProxy")
//    if (timer.isActive())
//        timer.stop();
 
   //reply->deleteLater();
 
   if (reply->error()) {
       qDebug() << "REPLY ERROR:" << reply->errorString() << reply->error();
 
       if (repeat && badProxyCount<3) {
           badProxyCount++;
           qDebug() << "badProxyCountGet: " << badProxyCount;
           delete reply;
           goto REPEATGET;
       }
   }
 
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ НАЧАЛО ////////////////////////
   replyHeaders.clear();
   QList<QByteArray> listHeaders = reply->rawHeaderList();
   foreach(QByteArray nameHeader, listHeaders) {
       QByteArray valueHeader = reply->rawHeader(nameHeader);
       replyHeaders.insert(nameHeader, valueHeader);
   }
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ КОНЕЦ ////////////////////////
 
   if (headers == showHeaders) HTTPHEADERS(reply);
 
   location = QByteArray::fromPercentEncoding(reply->rawHeader("Location"));
   if (!reply->rawHeader("Ajax-Location").isEmpty()) {
       location = QByteArray::fromPercentEncoding(reply->rawHeader("Ajax-Location"));
   }
   if (redirect == autoRedirect) {
       if (!location.isEmpty()) {
           lastUrl = reply->url().toString();
 
           redirectCount = 0;
           REDIRECT(qnam, howReadAnswer, showHeaders);
           return;
       }
   }
 
//    if (readAnswer) {
//        if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
//            answer = uncompress(reply->readAll());
//        } else {
//            answer = reply->readAll();
//        }
//    } else {
//        answerBytes = reply->readAll();
//    }
 
   answer.clear();
   answerBytes.clear();
 
   if (howReadAnswer == readAnswerToString) {
       if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
           answer = uncompress(reply->readAll());
       } else {
           answer = reply->readAll();
       }
   } else if (howReadAnswer == readAnswerToByteArray) {
       if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
           answerBytes = uncompress(reply->readAll());
       } else {
           answerBytes = reply->readAll();
       }
   } else if (howReadAnswer == readAnswerToOther) {
       if (reply->rawHeader("Content-Type").contains("image/gif")) {
           if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
               answerBytes = uncompress(reply->readAll());
           } else {
               answerBytes = reply->readAll();
           }
       } else {
           if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
               answer = uncompress(reply->readAll());
           } else {
               answer = reply->readAll();
           }
       }
   }
 
   lastUrl = reply->url().toString();
 
   delete reply;
}
 
void Thread::POST(QNetworkAccessManager &qnam, int howReadAnswer, int headers, int redirect, QByteArray contentType, bool repeat)
{
   QEventLoop loopPost;
   int badProxyCount=0;
 
   REPEATPOST:
 
   request.setRawHeader("Content-Type", contentType);
 
   reply = qnam.post(request, postData);
   reply->ignoreSslErrors();
 
   //if (proxyType == "NoUseProxy")
//    QTimer timer;
//    timer.start(30000);
//    connect(&timer, SIGNAL(timeout()), &loopPost, SLOT(quit()));
 
   QTimer::singleShot(60000, &loopPost, SLOT(quit()));
   connect(reply, SIGNAL(finished()), &loopPost, SLOT(quit()));
   loopPost.exec();
 
   //if (proxyType == "NoUseProxy")
//    if (timer.isActive())
//        timer.stop();
 
   //reply->deleteLater();
 
   if (reply->error()) {
       qDebug() << "REPLY ERROR:" << reply->errorString() << reply->error();
 
       if (repeat && badProxyCount<3) {
           badProxyCount++;
           qDebug() << "badProxyCountPost: " << badProxyCount;
           delete reply;
           goto REPEATPOST;
       }
   }
 
 
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ НАЧАЛО ////////////////////////
   replyHeaders.clear();
   QList<QByteArray> listHeaders = reply->rawHeaderList();
   foreach(QByteArray nameHeader, listHeaders) {
       QByteArray valueHeader = reply->rawHeader(nameHeader);
       replyHeaders.insert(nameHeader, valueHeader);
   }
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ КОНЕЦ ////////////////////////
 
 
   if (headers == showHeaders) HTTPHEADERS(reply);
 
   location = QByteArray::fromPercentEncoding(reply->rawHeader("Location"));
   if (!reply->rawHeader("Ajax-Location").isEmpty()) {
       location = QByteArray::fromPercentEncoding(reply->rawHeader("Ajax-Location"));
   }
   if (redirect == autoRedirect) {
       if (!location.isEmpty()) {
           lastUrl = reply->url().toString();
 
           redirectCount = 0;
           REDIRECT(qnam, howReadAnswer, showHeaders);
           return;
       }
   }
 
//    if (readAnswer) {
//        if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
//            answer = uncompress(reply->readAll());
//        } else {
//            answer = reply->readAll();
//        }
//    }
   if (howReadAnswer == readAnswerToString) {
       if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
           answer = uncompress(reply->readAll());
       } else {
           answer = reply->readAll();
       }
   } else if (howReadAnswer == readAnswerToByteArray) {
       if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
           answerBytes = uncompress(reply->readAll());
       } else {
           answerBytes = reply->readAll();
       }
   }
 
   lastUrl = reply->url().toString();
 
   delete reply;
}
 
void Thread::REDIRECT(QNetworkAccessManager &qnam, int howReadAnswer, int headers)
{
   QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
//    if (redirectUrl.isEmpty()) {
//        if (reply->rawHeader("Ajax-Location") == "registrationConfirm.html") {
//            redirectUrl = reply->url().resolved(QUrl(QString(reply->rawHeader("Ajax-Location"))));
//            //referer = redirectUrl.toEncoded();
//        } else {
//            redirectUrl = QUrl(QString(reply->rawHeader("Ajax-Location")));
//            request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
//            request.setRawHeader("Wicket-Ajax", QByteArray());
//            request.setRawHeader("Content-Type", QByteArray());
//        }
//    }
 
   qDebug() << "redirect url do: " << redirectUrl;
 
   //request.setRawHeader("Referer", "");
//    if (redirectUrl.toEncoded().startsWith("/")) {
//        redirectUrl = reply->url().resolved(redirectUrl);
//        qDebug() << "redirect url posle: " << redirectUrl;
//    }
 
   if (!redirectUrl.isEmpty() && redirectUrl.isRelative()) { //redirectUrl.toEncoded().startsWith("/")
       redirectUrl = reply->url().resolved(redirectUrl);
       qDebug() << "redirect url posle: " << redirectUrl;
   } else if (!reply->rawHeader("Ajax-Location").isEmpty()) {
//        if (redirectUrl.toString().endsWith(".html")) {
       request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
       request.setRawHeader("Wicket-Ajax", QByteArray());
//        }
       redirectUrl = reply->url().resolved(QUrl::fromPercentEncoding(reply->rawHeader("Ajax-Location")));
       qDebug() << "redirect url Ajax-Location posle: " << redirectUrl;
   } else if (redirectUrl.isEmpty()) {
       qDebug() << endl << this->objectName() << endl << endl << "NO REDIRECT!!!" << endl << endl << endl;
       return;
   }
 
 
 
   //request.setRawHeader("Referer", lastUrl.toUtf8());
   request.setRawHeader("Content-Type", QByteArray());
   request.setUrl(redirectUrl);
 
   QEventLoop loopRedirect;
   int badProxyCount=0;
 
   delete reply;
 
   REPEATREDIRECT:
 
   reply = qnam.get(request);
   reply->ignoreSslErrors();
 
   //if (proxyType == "NoUseProxy")
//    QTimer timer;
//    timer.start(30000);
//    connect(&timer, SIGNAL(timeout()), &loopRedirect, SLOT(quit()));
 
   QTimer::singleShot(60000, &loopRedirect, SLOT(quit()));
   connect(reply, SIGNAL(finished()), &loopRedirect, SLOT(quit()));
   loopRedirect.exec();
 
   //if (proxyType == "NoUseProxy")
//    if (timer.isActive())
//        timer.stop();
 
   //reply->deleteLater();
 
   qDebug() << reply->url();
   if (reply->error()) {
       qDebug() << "REPLY ERROR:" << reply->errorString() << reply->error();
 
       if (badProxyCount<3) {
           badProxyCount++;
           qDebug() << "badProxyCountRedirect: " << badProxyCount;
           delete reply;
           goto REPEATREDIRECT;
       }
   }
 
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ НАЧАЛО ////////////////////////
   replyHeaders.clear();
   QList<QByteArray> listHeaders = reply->rawHeaderList();
   foreach(QByteArray nameHeader, listHeaders) {
       QByteArray valueHeader = reply->rawHeader(nameHeader);
       replyHeaders.insert(nameHeader, valueHeader);
   }
///////////////////////////////// ЗАПИСЬ ЗАГОЛОВКОВ КОНЕЦ ////////////////////////
 
   if (headers == showHeaders) HTTPHEADERS(reply);
 
 
   if ((!reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().isEmpty() || !reply->rawHeader("Ajax-Location").isEmpty())
           && redirectCount < 33) {
       redirectCount++;
       REDIRECT(qnam, howReadAnswer, showHeaders);
   } else {
//        if (readAnswer) {
//            if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
//                answer = uncompress(reply->readAll());
//            } else {
//                answer = reply->readAll();
//            }
//        }
       if (howReadAnswer == readAnswerToString) {
           if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
               answer = uncompress(reply->readAll());
           } else {
               answer = reply->readAll();
           }
       } else if (howReadAnswer == readAnswerToByteArray) {
           if (reply->rawHeader("Content-Encoding").contains("gzip")) { //if (gzip)
               answerBytes = uncompress(reply->readAll());
           } else {
               answerBytes = reply->readAll();
           }
       }
 
       locationRedirect = QByteArray::fromPercentEncoding(reply->rawHeader("Location"));
       if (!reply->rawHeader("Ajax-Location").isEmpty()) {
           locationRedirect = QByteArray::fromPercentEncoding(reply->rawHeader("Ajax-Location"));
       }
       lastUrl = reply->url().toString();
       delete reply;
   }
}
 
void Thread::HTTPHEADERS(QNetworkReply *reply)
{
   if (!SHOWHEADERS) return;
 
 
   qDebug() << endl << this->objectName() << reply->url();
   qDebug() << "Request headers:  ";
   QList<QByteArray> reqHeaders = reply->request().rawHeaderList();
   //QList<QByteArray> reqHeaders = request.rawHeaderList();
   foreach (QByteArray reqName, reqHeaders)
   {
       QByteArray reqValue = reply->request().rawHeader(reqName);
       //QByteArray reqValue = request.rawHeader(reqName);
       qDebug() << reqName << ": " << reqValue;
   }
   qDebug() << "Reply headers:  ";
   QList<QByteArray> reqHeadersReply = reply->rawHeaderList();
   foreach( QByteArray reqName, reqHeadersReply )
   {
       QByteArray reqValue = reply->rawHeader( reqName );
       qDebug() << reqName << ": " << reqValue;
   }
}
 
QByteArray Thread::uncompress(const QByteArray &data)
{
   if (data.size() <= 4) {
       qWarning("uncompress: Input data is truncated");
       return QByteArray();
   }
 
   QByteArray result;
 
   int ret;
   z_stream strm;
   static const int CHUNK_SIZE = 1024;
   char out[CHUNK_SIZE];
 
   /* allocate inflate state */
   strm.zalloc = Z_NULL;
   strm.zfree = Z_NULL;
   strm.opaque = Z_NULL;
   strm.avail_in = data.size();
   strm.next_in = (Bytef*)(data.data());
 
   ret = inflateInit2(&strm, 15 +  32); // gzip decoding
   if (ret != Z_OK)
       return QByteArray();
 
   // run inflate()
   do {
       strm.avail_out = CHUNK_SIZE;
       strm.next_out = (Bytef*)(out);
 
       ret = inflate(&strm, Z_NO_FLUSH);
       Q_ASSERT(ret != Z_STREAM_ERROR);  // state not clobbered
 
       switch (ret) {
       case Z_NEED_DICT:
           ret = Z_DATA_ERROR;     // and fall through
       case Z_DATA_ERROR:
       case Z_MEM_ERROR:
           (void)inflateEnd(&strm);
           return QByteArray();
       }
 
       result.append(out, CHUNK_SIZE - strm.avail_out);
   } while (strm.avail_out == 0);
 
   // clean up and return
   inflateEnd(&strm);
   return result;
}
« Последнее редактирование: Июль 04, 2013, 07:30 от thechicho » Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #2 : Июль 04, 2013, 10:14 »

я такой код использую.
если поможет и как-то оптимизируете код, выложите тут свой вариант.

Спасибо! Но хотелось бы обойтись без QEventLoop и 6 подключений висящих на портах.
Пока что вижу что лучший вариант это вернуться на QHttp.
Наверно стоит написать свой класс на базе QSslSocket.

Как-то странно что QNetworkAccessManager  нельзя настроить так. В Qt5 тоже нет возможности сделать один поток?
Записан
thechicho
Гость
« Ответ #3 : Июль 04, 2013, 19:15 »

а чем плох QEventLoop?

//6 подключений висящих на портах
расскажите подробнее, что за 6 подключений? никогда не слышал о них
Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #4 : Июль 04, 2013, 19:50 »

6 подключений висящих на портах
расскажите подробнее, что за 6 подключений? никогда не слышал о них

QHttp делает 1 подключение к серверу.
А QNetworkAccessManager целых 6, при том это значение в коде прописано как const для десктопов.

Note: QNetworkAccessManager queues the requests it receives. The number of requests executed in parallel is dependent on the protocol. Currently, for the HTTP protocol on desktop platforms, 6 requests are executed in parallel for one host/port combination.

const int QHttpNetworkConnectionPrivate::defaultChannelCount = 6;

Откройте tcpview и подключитесь программой через QNetworkAccessManager увидите там больше одного подключения.

Это означает что если послать 6 QNetworkRequest то они будут обрабатываться одновременно, и могут вернуться назад не в том порядке.

http://www.prog.org.ru/topic_24065_0.html

Можно сделать с помощью QEventLoop задержку, но оно все-равно биндит резервные подключения.

Было бы прекрасно если в QNetworkAccessManager можно задать один паралельный запрос одновременно.

К стати проект тут: https://sourceforge.net/projects/bitcointrader/
« Последнее редактирование: Июль 04, 2013, 22:16 от IGHOR » Записан
thechicho
Гость
« Ответ #5 : Июль 05, 2013, 07:32 »

QNetworkAccessManager больше для работы с веб-сайтами подходит, получается.
для работы с сервером используйте сокеты.
Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #6 : Июль 06, 2013, 17:10 »

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

Если использовать QSslSocket для Http запросов, то один ответ может быть разбит на несколько пакетов которые надо соединить.
Вопрос как их правильно склеивать? Смотрите картинку.
Записан
thechicho
Гость
« Ответ #7 : Июль 06, 2013, 20:48 »

без понятия. для моих целей QNetworkAccessManager хватает.

https://ru.wikipedia.org/wiki/HTTP
https://tools.ietf.org/html/rfc2616
или гугл
Записан
thechicho
Гость
« Ответ #8 : Июль 06, 2013, 20:51 »

судя по http://forum.vingrad.ru/act-ST/f-466/t-344912.html
4 байта - в них содержится размер пакета.
\r\n - перевод строки. используется в протоколе http. более подробно смотрите в документации Улыбающийся
Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #9 : Июль 07, 2013, 12:12 »

судя по http://forum.vingrad.ru/act-ST/f-466/t-344912.html
4 байта - в них содержится размер пакета.
\r\n - перевод строки. используется в протоколе http. более подробно смотрите в документации Улыбающийся

Да, QNetworkAccessManager и QHttp это сами обрабатывают.
Странно что в одних разделенных пакетах Http ответа есть этот размер а в других нет.
Записан
thechicho
Гость
« Ответ #10 : Июль 08, 2013, 07:43 »

кстати, можете показать как вы делаете запрос?
по идее чтобы "склеить" достаточно
Код
C++ (Qt)
QByteArray & QByteArray::append ( const QByteArray & ba )

посмотрите
http://qt-project.org/doc/qt-4.8/network-securesocketclient.html
если Qt собиралась с примерами лежит примерно тут
C:\Qt\4.8.4-mingw4.4\examples\network\securesocketclient\securesocketclient.pro

возможно пригодятся заголовки при запросе к серверу по http-протоколу
Accept-Encoding: gzip,deflate // если ответ придет в gzip, распаковать можно QByteArray uncompress(const QByteArray &data) // для экономии трафика
Connection: keep-alive // и Connection: close // держать соединение открытым, если еще запросы планируются. закрыть - если последний запрос. типа меньше нагрузка на сервер.
Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #11 : Июль 08, 2013, 14:38 »

кстати, можете показать как вы делаете запрос?
по идее чтобы "склеить" достаточно
Код
C++ (Qt)
QByteArray & QByteArray::append ( const QByteArray & ba )

Дело в поддержке сервера метода ответа chunked.
Сдедал все сам с QSslSocket по документации http.
Записан
thechicho
Гость
« Ответ #12 : Июль 09, 2013, 19:23 »

выложите код (куски кода), конкретно этого вопроса. желательно с пояснениями, может кому-то в будущем время сэкономит.
и добавьте в заголовок темы "[РЕШЕНО]"
Записан
IGHOR
Крякер
****
Offline Offline

Сообщений: 390



Просмотр профиля WWW
« Ответ #13 : Июль 09, 2013, 19:41 »

Решение: использовать QSslSocket и читать данные по спецификации HTTP
http://ru.wikipedia.org/wiki/Chunked_transfer_encoding
Записан
thechicho
Гость
« Ответ #14 : Июль 09, 2013, 20:05 »

//и читать данные по спецификации HTTP
это не решение.
покажите как вы делаете обработку Transfer-Encoding: chunked средствами Qt
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.236 секунд. Запросов: 23.