This question is interesting, so let's do some research. I set up a nginx server with big keep alive timeout and wrote the simpliest Qt application:
QApplication a(argc, argv);
QNetworkAccessManager manager;
QNetworkRequest r(QUrl("http://myserver/"));
manager.get(r);
return a.exec();
Also I used the following command (in Linux console) to monitor connections and check if the problem reproduces at all:
watch -n 1 netstat -n -A inet
I took quick look at Qt sources and found that it uses QTcpSocket
and closes it in QHttpNetworkConnectionChannel::close
. So I opened the debugger console (Window → Views → Debugger log
in Qt Creator) and added a breakpoint while the process was paused:
bp QAbstractSocket::close
Note: this is for cdb (MS debugger), other debuggers require other commands. Another note: I use Qt with debug info, and this approach may not work without it.
After two minutes of waiting I got the backtrace of the close()
call!
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)
The class responsible for this action is QNetworkAccessCache
. It sets up timers and makes sure that its objects are deleted when QNetworkAccessCache::Node::timestamp
is in the past. And these objects are HTTP connections, FTP connections, and credentials.
Next, what is timestamp
? When the object is released, its timestamp is calculated in the following way:
node->timestamp = QDateTime::currentDateTime().addSecs(ExpiryTime);
And ExpiryTime = 120
is hardcoded.
All involved classes are private, and I found no way to prevent this from happening. So it's way simpler to send keep-alive requests each minute (at least now you know that 1 minute is safe enough), as the alternative is to rewrite Qt code and compile custom version.