2015-04-20 14 views
5

Ich versuche, eine dauerhafte Verbindung zwischen Client und Remote-Server mit Qt aufrechtzuerhalten. Meine Seite ist in Ordnung. Ich mache meine Kundenseite in Qt. Hier werde ich QNetworkAccessManager für die Anfrage Server mit Get-Methode (Teil der QNetworkRequest Methode) verwenden. Ich kann Anfragen senden und empfangen.Dauerhafte Verbindung mit QNetworkAccessManager in Qt

Aber nach einiger Zeit (ca. ~ 2 min) deutet der Client den Server an, die Verbindung wurde durch das automatische Buchen einer Anfrage geschlossen. Ich denke QNetworkAccessManager setzt ein Timeout für diese Verbindung. Ich möchte eine beständige Verbindung zwischen den Enden aufrechterhalten.

Ist meine Vorgehensweise korrekt, wenn nicht, kann mir jemand den richtigen Weg zeigen?

+1

scheint diese Frage für mich wirklich gültig zu sein. Wenn Sie eine Lösung finden, würden Sie gerne mit der Community teilen? Bitte geben Sie auch ein Code-Snippet an, damit SO-Ingenieure Ihnen mit Leichtigkeit helfen können. – Whoami

+1

Warum implementieren Sie nicht einen Heartbeat, um die Verbindung aufrecht zu erhalten? – dtech

+0

Wenn Ihr Server WebSockets unterstützt, können Sie http://doc.qt.io/qt-5/qtweb Sockets-Index.html für eine dauerhafte Verbindung zwischen Ihrem Client und Server auschecken. –

Antwort

2

Diese Frage ist interessant, also lasst uns etwas recherchieren. Ich habe einen nginx Server mit großen Keep-Alive-Timeout auf und schrieb die simpliest Qt-Anwendung:

QApplication a(argc, argv); 
QNetworkAccessManager manager; 
QNetworkRequest r(QUrl("http://myserver/")); 
manager.get(r); 
return a.exec(); 

Auch habe ich den folgenden Befehl ein (in Linux-Konsole) Verbindungen zu überwachen und zu prüfen, ob das Problem überhaupt wiedergibt:

Ich schaute schnell auf Qt Quellen und stellte fest, dass es QTcpSocket verwendet und schließt es in QHttpNetworkConnectionChannel::close. Also öffnete ich den Debugger-Konsole (Window → Views → Debugger log in Qt Creator) und hat einen Haltepunkt, während der Prozess unterbrochen wurde:

bp QAbstractSocket::close 

Hinweis: Dies ist für cdb (MS Debugger), andere Debugger benötigen andere Befehle. Noch ein Hinweis: Ich verwende Qt mit Debug-Informationen, und dieser Ansatz funktioniert möglicherweise nicht ohne.

Nach zwei Minuten Wartezeit habe ich das Backtrace der close() Anruf!

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) 

Die Klasse verantwortlich für diese Aktion ist QNetworkAccessCache. Es stellt Timer ein und stellt sicher, dass seine Objekte gelöscht werden, wenn QNetworkAccessCache::Node::timestamp in der Vergangenheit liegt. Und diese Objekte sind HTTP-Verbindungen, FTP-Verbindungen und Anmeldeinformationen.

Als nächstes, was ist timestamp? Wenn das Objekt freigegeben wird, wird sein Zeitstempel in der folgenden Weise berechnet:

node->timestamp = QDateTime::currentDateTime().addSecs(ExpiryTime); 

Und ExpiryTime = 120 hartcodiert ist.

Alle beteiligten Klassen sind privat, und ich habe keine Möglichkeit gefunden, dies zu verhindern. So ist es viel einfacher, Keep-Alive-Anfragen jede Minute zu senden (zumindest wissen Sie jetzt, dass 1 Minute sicher genug ist), da die Alternative darin besteht, Qt-Code neu zu schreiben und eine benutzerdefinierte Version zu kompilieren.

0

Ich würde per Definition sagen, eine 2-Minuten-Timeout-Verbindung qualifiziert sich für persistent. Ich meine, wenn es nicht hartnäckig wäre, müssten Sie sich bei jeder Anfrage neu verbinden. 2 Minuten sind im Vergleich zu anderer Software ziemlich großzügig bemessen. Aber es wird nach einer gewissen Zeit der Inaktivität irgendwann auslaufen und das ist eine gute Sache, die nicht überraschen sollte. Einige Software erlaubt es, das Zeitlimit zu ändern, aber aus Pavels Untersuchung würde es erscheinen, dass im Falle von Qt das Timeout fest codiert ist.

Zum Glück ist die Lösung einfach, rig einfach einen Timer, um einen Herzschlag (nur eine Dummy-Anfrage, nicht mit "Heartbeat-Netzwerk") alle 1 Minute oder so zu senden, um die Verbindung am Leben zu halten. Bevor Sie Ihre Verbindung verwenden, deaktivieren Sie den Timer, und starten Sie den Timer neu, nachdem Sie die Verbindung beendet haben.