Здравствуйте.
Мы пишем десктопное приложение на 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".