Russian Qt Forum

Qt => Работа с сетью => Тема начата: IGHOR от Июль 04, 2013, 00:51



Название: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: IGHOR от Июль 04, 2013, 00:51
Есть у меня программа Qt Bitcoin Trader.
Решил наконец то перейти с QHttp на QNetworkAccessManager.
Но закрались подводные камни с параметром nonce.
Все запросы должны доходить до сервера в той последовательности что были отправлены.
В QHttp это работало как надо. Но не хватало возможности задать таймаут запроса и тп.

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

В сервер надо посылать число с постоянным инкрементом.
1,2,3,4, если придет 1,2,4,3 то будет ошибка.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 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;
}


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 04, 2013, 10:14
я такой код использую.
если поможет и как-то оптимизируете код, выложите тут свой вариант.

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

Как-то странно что QNetworkAccessManager  нельзя настроить так. В Qt5 тоже нет возможности сделать один поток?


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 04, 2013, 19:15
а чем плох QEventLoop?

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


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 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/


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 05, 2013, 07:32
QNetworkAccessManager больше для работы с веб-сайтами подходит, получается.
для работы с сервером используйте сокеты.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 06, 2013, 17:10
QNetworkAccessManager больше для работы с веб-сайтами подходит, получается.
для работы с сервером используйте сокеты.

Если использовать QSslSocket для Http запросов, то один ответ может быть разбит на несколько пакетов которые надо соединить.
Вопрос как их правильно склеивать? Смотрите картинку.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 06, 2013, 20:48
без понятия. для моих целей QNetworkAccessManager хватает.

https://ru.wikipedia.org/wiki/HTTP
https://tools.ietf.org/html/rfc2616
или гугл


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 06, 2013, 20:51
судя по http://forum.vingrad.ru/act-ST/f-466/t-344912.html
4 байта - в них содержится размер пакета.
\r\n - перевод строки. используется в протоколе http. более подробно смотрите в документации :)


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 07, 2013, 12:12
судя по http://forum.vingrad.ru/act-ST/f-466/t-344912.html
4 байта - в них содержится размер пакета.
\r\n - перевод строки. используется в протоколе http. более подробно смотрите в документации :)

Да, QNetworkAccessManager и QHttp это сами обрабатывают.
Странно что в одних разделенных пакетах Http ответа есть этот размер а в других нет.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 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 // держать соединение открытым, если еще запросы планируются. закрыть - если последний запрос. типа меньше нагрузка на сервер.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 08, 2013, 14:38
кстати, можете показать как вы делаете запрос?
по идее чтобы "склеить" достаточно
Код
C++ (Qt)
QByteArray & QByteArray::append ( const QByteArray & ba )

Дело в поддержке сервера метода ответа chunked.
Сдедал все сам с QSslSocket по документации http.


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: thechicho от Июль 09, 2013, 19:23
выложите код (куски кода), конкретно этого вопроса. желательно с пояснениями, может кому-то в будущем время сэкономит.
и добавьте в заголовок темы "[РЕШЕНО]"


Название: Re: QNetworkAccessManager и параметр Nonce
Отправлено: IGHOR от Июль 09, 2013, 19:41
Решение: использовать QSslSocket и читать данные по спецификации HTTP
http://ru.wikipedia.org/wiki/Chunked_transfer_encoding


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: thechicho от Июль 09, 2013, 20:05
//и читать данные по спецификации HTTP
это не решение.
покажите как вы делаете обработку Transfer-Encoding: chunked средствами Qt


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: IGHOR от Июль 13, 2013, 21:07
Код:
	int currentLineDataType=0;
while(socketSender->bytesAvailable())
{
static QByteArray currentLine;
currentLine=socketSender->readLine();

if(currentLine.isEmpty())continue;
if(currentLine.startsWith("HTTP/1"))
{
if(!buffer.isEmpty())buffer.clear();
currentLineDataType=1;
endOfPacket=false;
continue;
}

switch(currentLineDataType)
{
case 0:
if(nextPacketMastBeSize&&currentLine.size()>1&&currentLine.size()<=8&&currentLine.right(2)=="\r\n")
{
currentLine.remove(currentLine.size()-2,2);
quint16 currentChunkSize=currentLine.toUShort(0,16);
if(currentChunkSize==0)endOfPacket=true;
else packetChunkSize+=currentChunkSize;
nextPacketMastBeSize=false;
break;
}
else
{
if(currentLine.size()>1&&currentLine.right(2)=="\r\n")
{
currentLine.remove(currentLine.size()-2,2);
nextPacketMastBeSize=true;
}
buffer.append(currentLine);
}
break;
case 1:
if(currentLine.endsWith("chunked")){packetIsChunked=true;break;}
if(currentLine!="\r\n")break;
currentLineDataType=0;
nextPacketMastBeSize=true;
break;
}
if(endOfPacket)
{
if(packetChunkSize<buffer.size())buffer.remove(0,buffer.size()-packetChunkSize);

emit dataReceived(buffer);

sendPendingData();
}
}


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: IGHOR от Июль 15, 2013, 14:47
Остался еще вопрос. Есть ли еще какой-то идентификатор пакета QSslSocket чтобы знать что тот что отправлен был получен.
Например отправляю пакеты и по очереди получаю ответы:
1,2,3
А отправил 4 пакет и вышел таймаут, отсылаю следующий пакет номер 5, и тут внезапно приходит ответ от 4 пакета.
Можно ли задать пакету id или есть другие варианты решения проблемы?


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: thechicho от Июль 15, 2013, 16:18
не отсылать пакет 5, пока не придет ответ от 4 пакета?


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: IGHOR от Июль 15, 2013, 16:46
не отсылать пакет 5, пока не придет ответ от 4 пакета?
Ну это так и работает. Но выходит таймаут, например 5 секунд. И шлю следующий пакет.
А после этого приходит 4.
Делать abort и опять connect это слишком долго.


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: thechicho от Июль 15, 2013, 17:13
имелось в виду увеличить таймаут, раз обязательно условие очередности прихода пакетов на сервер.
либо, отсылать 5 пакет сразу за 4ым или через какой-то промежуток времени, не дожидаясь ответа от 4ого. так сделать, если есть уверенность, что 4ый пакет 100500 дойдет до сервера и 5ый пакет никак не сможет его обогнать (я хз как работают сокеты, но вроде как позже ушел, позже должен прийти)
или еще как-нибудь :)


Название: Re: QNetworkAccessManager и параметр Nonce [РЕШЕНО]
Отправлено: IGHOR от Июль 15, 2013, 18:26
Там некоторые пакеты обязательны к получению, а некоторые не важные можно проигнорировать.
И надо сделать так чтобы важный пакет сразу отправлялся, а не ждал 5 секунд на ответ не важного.
В общем буду думать об оптимизации :)