Этот вопрос интересен, поэтому давайте проведем небольшое исследование. Я настроил сервер nginx с большим тайм-аутом поддержки и написал самое простое приложение Qt:
QApplication a(argc, argv);
QNetworkAccessManager manager;
QNetworkRequest r(QUrl("http://myserver/"));
manager.get(r);
return a.exec();
Также я использовал следующую команду (в консоли Linux) для мониторинга подключений и проверки, воспроизводится ли проблема вообще:
watch -n 1 netstat -n -A inet
Я быстро просмотрел исходники Qt и обнаружил, что он использует QTcpSocket
и закрывает его в QHttpNetworkConnectionChannel::close
. Итак, я открыл консоль отладчика (Window → Views → Debugger log
в Qt Creator) и добавил точку останова, когда процесс был приостановлен:
bp QAbstractSocket::close
Примечание: это для cdb (отладчик MS), для других отладчиков требуются другие команды. Еще одно замечание: я использую Qt с отладочной информацией, и без нее этот подход может не работать.
После двух минут ожидания я получил обратную связь звонка close()
!
QAbstractSocket::close qabstractsocket.cpp 2587 0x13fe12600
QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate qhttpnetworkconnection.cpp 110 0x13fe368c4
QHttpNetworkConnectionPrivate::`scalar deleting destructor' untitled 0x13fe3db27
QScopedPointerDeleter<QObjectData>::cleanup qscopedpointer.h 62 0x140356759
QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData>>::~QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData>> qscopedpointer.h 99 0x140355700
QObject::~QObject qobject.cpp 863 0x14034b04f
QHttpNetworkConnection::~QHttpNetworkConnection qhttpnetworkconnection.cpp 1148 0x13fe35fa2
QNetworkAccessCachedHttpConnection::~QNetworkAccessCachedHttpConnection untitled 0x13fe1e644
QNetworkAccessCachedHttpConnection::`scalar deleting destructor' untitled 0x13fe1e6e7
QNetworkAccessCachedHttpConnection::dispose qhttpthreaddelegate.cpp 170 0x13fe1e89e
QNetworkAccessCache::timerEvent qnetworkaccesscache.cpp 233 0x13fd99d07
(next lines are not interesting)
За это действие отвечает класс QNetworkAccessCache
. Он устанавливает таймеры и гарантирует, что его объекты будут удалены, когда QNetworkAccessCache::Node::timestamp
останется в прошлом. Этими объектами являются HTTP-соединения, FTP-соединения и учетные данные.
Далее, что такое timestamp
? Когда объект освобождается, его метка времени вычисляется следующим образом:
node->timestamp = QDateTime::currentDateTime().addSecs(ExpiryTime);
И ExpiryTime = 120
жестко запрограммировано.
Все задействованные классы являются закрытыми, и я не нашел способа предотвратить это. Так что намного проще отправлять запросы на поддержку каждую минуту (по крайней мере, теперь вы знаете, что 1 минута достаточно безопасна), поскольку альтернативой является переписывание кода Qt и компиляция пользовательской версии.
person
Pavel Strakhov
schedule
20.04.2015