2015-04-20 15 views
5

Sto provando a mantenere una connessione persistente tra client e server remoto utilizzando Qt. Il mio lato severo va bene. Sto facendo il mio lato client in Qt. Qui userò QNetworkAccessManager per richiedere server con metodo get (parte del metodo QNetworkRequest). Sarò in grado di inviare e ricevere richieste.Connessione persistente con QNetworkAccessManager in Qt

Ma dopo qualche tempo (circa ~ 2 min) il cliente è intimating server, la connessione ha chiuso inviando automaticamente una richiesta. Penso che QNetworkAccessManager sta impostando un timeout per questa connessione. Voglio mantenere una connessione persistente tra le estremità.

Il mio approccio è corretto, se no, qualcuno può guidarmi nel percorso corretto?

+1

questa domanda sembra essere davvero valida per me. Se trovi una soluzione, ti dispiacerebbe condividere con la comunità? Si prega di fornire anche uno snippet di codice, in modo che gli ingegneri della SO possano aiutarvi con facilità. – Whoami

+1

Perché non implementare l'invio di un heartbeat per mantenere attiva la connessione? – dtech

+0

Se il server supporta WebSockets, è possibile controllare http://doc.qt.io/qt-5/qtwebsockets-index.html per una connessione persistente tra il client e il server. –

risposta

2

Questa domanda è interessante, quindi facciamo qualche ricerca. Ho messo su un server nginx con grande timeout tenere in vita e ha scritto la più semplice applicazione Qt:

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

Inoltre ho usato il seguente comando (in consolle Linux) per monitorare le connessioni e verificare se il problema riproduce affatto:

watch -n 1 netstat -n -A inet 

Ho dato una rapida occhiata alle fonti Qt e ho scoperto che utilizza QTcpSocket e lo chiude in QHttpNetworkConnectionChannel::close. Così ho aperto la console debugger (Window → Views → Debugger log in Qt Creator) e aggiunto un punto di interruzione, mentre il processo è stato messo in pausa:

bp QAbstractSocket::close 

Nota: questo è per CDB (debugger MS), altri debugger richiede altri comandi. Un'altra nota: io uso Qt con informazioni di debug e questo approccio potrebbe non funzionare senza di esso.

Dopo due minuti di attesa ho avuto la backtrace della chiamata 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) 

La classe responsabile di questa azione è QNetworkAccessCache. Imposta i timer e si assicura che i suoi oggetti siano cancellati quando QNetworkAccessCache::Node::timestamp è nel passato. E questi oggetti sono connessioni HTTP, connessioni FTP e credenziali.

Quindi, che cos'è timestamp? Quando l'oggetto viene rilasciato, il suo timestamp viene calcolato nel seguente modo:

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

E ExpiryTime = 120 è hardcoded.

Tutte le classi coinvolte sono private e non ho trovato alcun modo per impedire che ciò accada. Quindi è molto più semplice inviare richieste keep-alive ogni minuto (almeno ora sai che 1 minuto è abbastanza sicuro), in quanto l'alternativa è riscrivere il codice Qt e compilare la versione personalizzata.

0

Direi che per definizione, una connessione di timeout di 2 minuti è valida per il persistente. Voglio dire se non fosse persistente, dovresti riconnetterti ad ogni richiesta. 2 minuti sono abbastanza generosi rispetto ad altri software là fuori. Ma è impostato per scadere dopo un periodo di inattività e questa è una buona cosa che non dovrebbe sorprendere. Alcuni software consentono di modificare il periodo di timeout, ma dall'indagine di Pavel appare nel caso di Qt il timeout è hardcoded.

Fortunatamente la soluzione è semplice, basta impostare un timer per inviare un heartbeat (solo una richiesta fittizia, non confondere con "heartbeat network") ogni 1 minuto circa per mantenere viva la connessione. Prima di utilizzare la connessione, disattivare il timer e, una volta terminata la connessione, riavviare il timer.

Problemi correlati