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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: "пустые" параллельные tcp-коннекты  (Прочитано 5050 раз)
MonoSlon
Гость
« : Январь 28, 2013, 15:38 »

Здравствуйте.

Мы пишем десктопное приложение на Qt 4.8.2. Приложение, помимо всего прочего, запрашивает по http и https различную информацию с наших веб-серверов, используя QNetworkAccessManager.

Выяснилось, что приложение открывает одновременно несколько tcp-соединений с вебсервером, при этом используются не все коннекты. Эти пустые коннекты висят до тех пор, пока либо приложение не закроется, либо веб-сервер не закроет их по таймауту.
Причем, в некоторых случаях, соединение устанавливается и сразу же закрывается посылкой пакета от клиента с флагами ACK+RST
выглядит это примерно так:
CLNTIP.51584 > SRVIP.8443: S 2756740918:2756740918(0)
SRVIP.8443 > CLNTIP.51584: . ack 1 win 12
CLNTIP.51584 > SRVIP.8443: R 1:1(0) ack 1 win 0

пример кода, который воспроизводит такое поведение:
file main.cpp:
Код:
#include <QCoreApplication>
#include <QTimer>
#include <Sample.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Sample obj;

    for (int i = 0; i < 3; i++) {
        obj.makeRequest();
    }

    while(true) {
        Sleep(1000);
        obj.makeRequest();
    }

    int ret = a.exec();
    return ret;
}
file sample.h
Код:
#ifndef SAMPLE_H
#define SAMPLE_H
#include <QObject>
#include <QList>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QSslError>

class Sample : public QObject
{
    Q_OBJECT
public:
    explicit Sample(QObject *parent = 0);
    void startTest();
    void makeRequest();
signals:
public slots:
    void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
    void onTimer();
    void onRequestFinish();
    void onError(QNetworkReply::NetworkError error);
private:
   QNetworkAccessManager *_manager;
};
#endif // SAMPLE_H
file sample.cpp
Код:
#include <Sample.h>
#include <QCoreApplication>
#include <QDebug>
#include <QUrl>
#include <QtNetwork/QNetworkRequest>

Sample::Sample(QObject *parent)
    : QObject(parent), _manager(new QNetworkAccessManager(this))
{
    connect(this->_manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
            this, SLOT(sslErrors(QNetworkReply *, const QList<QSslError>&)));
}

void Sample::startTest()
{
    makeRequest();
}

void Sample::makeRequest()
{
    QUrl request("https://localhost:8443/restapi?method=somemethod");
    QNetworkReply *reply = (1 == 1)
        ? this->_manager->get(QNetworkRequest(request))
        : this->_manager->post(QNetworkRequest(request), request.encodedQuery());

    connect(reply, SIGNAL(finished()), this, SLOT(onRequestFinish()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));

    qDebug() << "makeRequest" << request;
}

void Sample::onRequestFinish()
{
    qDebug() << "onRequestFinish";
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(QObject::sender());
    reply->deleteLater();
    QString response = QString::fromUtf8(reply->readAll());
    QNetworkReply::NetworkError error = reply->error();
    qDebug() << response << error;
}

void Sample::onError(QNetworkReply::NetworkError error)
{
    qDebug() << "error" << error;
}

void Sample::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
    qDebug() << "sslErrors";
    Q_FOREACH(QSslError error, errors) {
        qDebug() << error;
    }
    reply->ignoreSslErrors();
}

void Sample::onTimer()
{
    QCoreApplication::quit();
}

Как я понял, Qt создает такие "запасные" коннекты, чтобы повысить скорость выполнения параллельных запросов, и, наверное, наиболее целесообразно это для мобильных и приложений и для браузеров (например, хром тоже окрывает дополнительный коннект).

Есть ли возможность запретить приложению открывать такие "запасные" каналы? А то почти все логи веб-сервера забиты записями "400 bad request".
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #1 : Январь 28, 2013, 16:01 »

Этот пример показывает, что вы генерируете кучу запросов, которые не обрабатываются в силу не запущенной очереди сообщений.
Записан
MonoSlon
Гость
« Ответ #2 : Январь 28, 2013, 16:12 »

отнюдь, все запросы обрабатываются. но при первых трех запросах приложение открывает сразу 6 каналов (const int QHttpNetworkConnectionPrivate::defaultChannelCount = 6; оно ?)
но сами запросы проходят максимум по трем сокетам, остальные три висят пустые.

Записан
MonoSlon
Гость
« Ответ #3 : Январь 28, 2013, 16:18 »

Прошу прощения за нубский вопрос.. А как запустить очередь сообщений? Улыбающийся Или, другими словами, что я делаю не так? Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #4 : Январь 28, 2013, 16:28 »

Прошу прощения за нубский вопрос.. А как запустить очередь сообщений? Улыбающийся Или, другими словами, что я делаю не так? Улыбающийся
QCoreApplication::exec как раз ее и запускает.
И как раз в этом цикле обрабатывается select для сокетов сетевых подключений.
Записан
MonoSlon
Гость
« Ответ #5 : Январь 28, 2013, 17:30 »

переделал вот так:
Код:
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Sample obj;
    QTimer::singleShot(30000, &obj, SLOT(startTest()));
    int ret = a.exec();
    return ret;
}
соответственно, код выполнения запросов перенес в public slot Sample::startTest().

Результат не изменился, приложение открывает 6 каналов, все запросы прошли только по одному.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #6 : Январь 28, 2013, 18:46 »

Результат не изменился, приложение открывает 6 каналов, все запросы прошли только по одному.
Я публичных рычагов изменить значение по умолчанию тоже не нашел.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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