Постоянное соединение с использованием QNetworkAccessManager в Qt

Я пытаюсь поддерживать постоянное соединение между клиентом и удаленным сервером с помощью Qt. Моя разорванная сторона в порядке. Я делаю свою клиентскую часть в Qt. Здесь я буду использовать QNetworkAccessManager для запроса сервера с помощью метода get (часть метода QNetworkRequest). Я смогу отправлять и получать запросы.

Но через некоторое время (примерно ~ 2 минуты) клиент сообщает серверу, соединение закрывается, автоматически отправляя запрос. Я думаю, что QNetworkAccessManager устанавливает тайм-аут для этого соединения. Я хочу поддерживать постоянную связь между концами.

Верен ли мой подход, если нет, может ли кто-нибудь направить меня на правильный путь?


person vgokul129    schedule 20.04.2015    source источник
comment
этот вопрос кажется мне действительно актуальным. Если вы найдете решение, не могли бы вы поделиться с сообществом? Пожалуйста, предоставьте также фрагмент кода, чтобы инженеры SO могли легко вам помочь.   -  person Whoami    schedule 20.04.2015
comment
Почему бы не реализовать отправку пульса, чтобы поддерживать соединение?   -  person dtech    schedule 20.04.2015
comment
Если ваш сервер поддерживает WebSockets, вы можете проверить doc.qt.io/ qt-5/qtwebsockets-index.html для постоянного соединения между вашим клиентом и сервером.   -  person Cameron Tinker    schedule 20.04.2015
comment
Кэмерон, спасибо за ссылку, но инженер так привередлив к возможностям QTNetwork Manager. у вас есть какие-нибудь мысли по этому поводу?   -  person Whoami    schedule 20.04.2015
comment
@ddrive, любая ссылка определенно должна помочь, и мы очень признательны.   -  person Whoami    schedule 20.04.2015


Ответы (2)


Этот вопрос интересен, поэтому давайте проведем небольшое исследование. Я настроил сервер 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

Я бы сказал, что по определению 2-минутное соединение с тайм-аутом считается постоянным. Я имею в виду, что если бы он не был постоянным, вам пришлось бы повторно подключаться при каждом запросе. 2 минуты довольно много по сравнению с некоторыми другими программами. Но он настроен на тайм-аут после периода бездействия, и это хорошо, что не должно удивлять. Некоторое программное обеспечение позволяет изменять период тайм-аута, но из исследования Павла следует, что в случае с Qt тайм-аут жестко запрограммирован.

К счастью, решение простое, просто установите таймер для отправки сердцебиения (просто фиктивный запрос, не путайте с «сеть сердцебиения») каждую минуту или около того, чтобы поддерживать соединение. Прежде чем использовать подключение, отключите таймер, а после завершения подключения перезапустите таймер.

person dtech    schedule 21.04.2015