1

まず、このクラスが作成されるたびに初期化プロセスをトリガーしたいと思います。(既知のホストの DNS ルックアップ、および指定された数のスロットでのホストとの事前ハンドシェイク - これは、テストが完了するとハードコーディングされません) - すべてのクラスが作成されている間、構成が読み取られている間など。

次に、特定のホストに存在する許可された (そして開かれた) スロットに応じて、並列化されたリクエストの送信を許可したいと思います。

率直に言って、次のコードには複数の問題があります。

  • Google は、複数のリクエストが同時にこのホストに送信されると、x 番号またはリクエストが終了信号をトリガーし、その信号がリダイレクト チェックを呼び出し、最初のリクエストがリダイレクトされると、壊滅的な障害を引き起こすようです。最初の返信が返ってきたようで、x 個のエラー メッセージが表示されます。
  • 同じ理由で httpFinished から deleteLater() を呼び出せないようです
  • キュー内の次のリクエストを開始するために、リクエストのスロット番号が終了するのを待つ方法が見つかりませんでした

主な目標は、単一のネットワーク クラスを使用して複数の 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

ネットワーク.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

ネットワーク.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 にまったく慣れていないことに注意してください。

助けてくれませんか、輝かしい見知らぬ人よ?:)

よろしく; ワンアイドスペースフィッシュ

4

0 に答える 0