Проблемы инициализации и асинхронизации QT NetworkManager

Во-первых, я хотел бы запустить процесс инициализации всякий раз, когда этот класс был создан. (Поиск DNS для известных хостов и предварительное рукопожатие с хостами через указанное количество слотов — это не должно быть жестко закодировано после того, как оно было протестировано) — пока создаются все классы, читается конфигурация и т. Д.

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

Откровенно говоря, есть несколько проблем со следующим кодом;

  • Похоже, что Google перенаправляет, когда несколько запросов одновременно к этому хосту приводят к катастрофическому сбою, когда число x или запрос запускают законченный сигнал, и эти сигналы вызывают мою проверку перенаправления, и первый запрос перенаправляется, и я похоже, что первый ответ получен, с x сообщениями об ошибках.
  • Я не могу вызвать deleteLater () из httpFinished по той же причине
  • Я не смог найти способ дождаться окончания слота запроса, чтобы начать следующий запрос в очереди

Основной целью будет сбор данных из нескольких API с использованием одного сетевого класса, эти запросы могут выполняться одновременно, а могут и нет.
Также будет другой запрос, отправляемый как POST и т. Д. может быть 1 класс / API?

Обратите внимание, что код является всего лишь тестом концепции и только для целей тестирования, и его следует очищать после того, как он был исправлен, это не то, как я предполагал, что он будет работать вообще.

nebula.pro

QT += core network
QT -= gui

TARGET = nebula
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
network.cpp

HEADERS += \
network.h

network.h

#ifndef NETWORK_H
#define NETWORK_H

#include <QObject>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QSslConfiguration>
#include <QEventLoop>

class network : public QObject
{
Q_OBJECT

public:
explicit network(QObject *parent = 0);
~network();
void sendGet(const QUrl &url);

private:
QNetworkAccessManager networkAccessManager;
QHash<QString, QByteArray> usedSession;
QNetworkReply *reply;
QUrl url;
Q_INVOKABLE void init();
void replyFinished(QUrl &url, QNetworkReply *reply);
QList<QString> provideTcpHosts();
QList<QString> provideSslHosts();
QEventLoop eventLoop;

private slots:
void httpError();
void sslErrors(const QList<QSslError> &errors);
void httpFinished();
};

#endif // NETWORK_H

network.cpp

#include "network.h"
/**
* @brief network::network
* initialazing pre-networking initialization once the eventpool is ready
* @param parent
*/
network::network(QObject *parent) : QObject(parent)
{
QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
}

network::~network()
{
networkAccessManager.deleteLater();
}

/**
* @brief network::init
* dns chache warming for all hosts and pre-connecting to all hosts via 4 sockets
*/
void network::init()
{
QList<QString> tcpHosts = provideTcpHosts();
QList<QString> sslHosts = provideSslHosts();

// tcp hosts initialazation
for( int i=0; i<tcpHosts.count(); ++i )
{
// pre-dns lookup cache warming
QHostInfo::lookupHost(tcpHosts[i], 0, 0);
qDebug() << "pre-dns lookup cache warming for: " + tcpHosts[i];
// tcp pre-handshake with known hosts over 4 sockets with known http hosts
for(int a=0; a<4; ++a)
{
networkAccessManager.connectToHost(tcpHosts[i], 80);
qDebug() << "connecting " + QString::number(a+1) + "th socket for " + tcpHosts[i];
}

}

// tcp hosts initialazation
for( int i=0; i<sslHosts.count(); ++i )
{
// pre-dns lookup cache warming
QHostInfo::lookupHost(sslHosts[i], 0, 0);
qDebug() << "pre-dns lookup cache warming for: " + sslHosts[i];

// tcp pre-handshake with known hosts over 4 sockets with known http hosts
for(int a=0; a<4; ++a)
{
networkAccessManager.connectToHostEncrypted(sslHosts[i], 443);
qDebug() << "connecting " + QString::number(a+1) + "th socket for " + sslHosts[i];
}
}
}

/**
* @brief network::replyFinished
* storing previous ssl session tickets for re-use, and error handling for finished requests
* @param url
* @param reply
*/
void network::replyFinished(QUrl &url, QNetworkReply *reply)
{
if(!usedSession.contains((QString)url.toString()))
{
usedSession.insert((QString)url.toString(), (QByteArray)reply->sslConfiguration().sessionTicket());
qDebug() << "saved ssl session ticket for" + url.toString();
}

reply->deleteLater();
}

/**
* @brief network::sendGet
* sending a simple GET request to specified url
* @param url
*/
void network::sendGet(const QUrl &url)
{
connect(&networkAccessManager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));

qDebug() << "Sending a GET request to" + (QString)url.toString();
QNetworkRequest request;
request.setUrl(url);
request.setRawHeader("User-Agent", "nebula");

// reusing an ssl session ticket if exists for url
if(usedSession.contains((QString)url.toString()))
{
QSslConfiguration qssl;
qssl.setSslOption(QSsl::SslOptionDisableSessionPersistence, false);
qssl.setSessionTicket(usedSession.value((QString)url.toString()));
request.setSslConfiguration(qssl);
qDebug() << "used ssl session ticket for" + url.toString();
}

reply = networkAccessManager.get(request);

connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(httpError()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
}

/**
* @brief network::provideTcpHosts
* @return
*/
QList<QString> network::provideTcpHosts()
{
return QList<QString>()
<< (QString)"http://www.google.com"<< (QString)"http://www.bing.com";
}

/**
* @brief network::provideSslHosts
* @return
*/
QList<QString> network::provideSslHosts()
{
return QList<QString>()
<< (QString)"https://www.ssllabs.com/ssltest/";
}

/*SLOTS*/

/**
* @brief network::slotTcpError
* @param tcpError
*/
void network::httpError()
{
qDebug() << "QNetworkRequest::HttpStatusCodeAttribute " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute ) << "received";
qDebug() << reply->errorString();
reply->deleteLater();
}

/**
* @brief network::slotSslErrors
* @param sslErrors
*/
void network::sslErrors(const QList<QSslError> &errors)
{
QString errorString;
foreach (const QSslError &error, errors) {
if (!errorString.isEmpty())
errorString += ", ";
errorString += error.errorString();
}

qDebug() << "ssl error recieved: " + errorString;

reply->deleteLater();
}

void network::httpFinished()
{
// possible redirect url
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);

if (!redirectionTarget.isNull()) {
this->sendGet(reply->url().resolved(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()));
} else {
qDebug() << "QNetworkRequest::HttpStatusCodeAttribute " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute ) << "received ";
qDebug() << reply->errorString();
qDebug() << reply->readAll();
}
}

main.cpp

#include <QCoreApplication>
#include <network.h>

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
network networkAccessManager;

for(int i = 0; i < 50; ++i)
{
networkAccessManager.sendGet((QString)"http://www.google.com");
}

return a.exec();
}

Пожалуйста, обратите внимание, я довольно новичок в продвинутых проектах C ++ и QT, этот проект частично -но будет использоваться для моего удивительного проекта, как только его открутить чтобы помочь мне быть знакомым с этими темами.

Не могли бы вы помочь мне, о славный незнакомец? 🙂

С уважением;
OneEyedSpaceFish

1

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы [email protected]