Qt中使用QNetworkAccessManager实现持久连接

6
我试图使用Qt维护客户端和远程服务器之间的持久连接。我的服务器端没有问题,我正在使用Qt编写客户端。在此过程中,我将使用QNetworkAccessManager通过get方法向服务器发出请求(作为QNetworkRequest方法的一部分)。我能够发送和接收请求。
但是在一段时间之后(大约2分钟左右),客户端会自动通过发送请求通知服务器连接已关闭。我认为QNetworkAccessManager为此连接设置了超时。我想在两端之间维护一个持久连接。
我的方法是否正确?如果不是,有谁能指导我走正确的路线吗?

1
这个问题对我来说似乎非常有效。如果你找到解决方案,是否愿意与社区分享?请提供一些代码片段,这样 Stack Overflow 的工程师就可以方便地帮助你。 - Whoami
1
为什么不实现发送心跳以保持连接的活性? - dtech
如果你的服务器支持WebSockets,你可能想查看http://doc.qt.io/qt-5/qtwebsockets-index.html,以在客户端和服务器之间建立持久连接。 - Cameron Tinker
Cameron,感谢你的推荐,但工程师非常关注 QTNetwork Manager 的可能性。你对此有什么想法吗? - Whoami
@ddrive,任何链接都肯定会有所帮助,非常感谢。 - Whoami
2个回答

4
这是一个有趣的问题,让我们做一些研究。我设置了一个带有长连接保持时间的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中关闭它。因此,在进程暂停时,我打开了调试器控制台(在Qt Creator中点击Window → Views → Debugger log),并添加了断点:

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代码并编译自定义版本。


1
根据定义,2分钟的超时连接符合持久性。我的意思是,如果它不是持久的,你每次请求都必须重新连接。相比其他软件,2分钟已经非常慷慨了。但它被设置为在一段时间内无活动后最终超时,这是一件好事情,不应该让人感到惊讶。有些软件允许更改超时时间,但从Pavel的调查结果来看,在Qt的情况下,超时时间是硬编码的。
幸运的是,解决方案很简单,只需设置定时器,每1分钟或更长时间发送一个心跳(只是一个虚假请求,不要与“心跳网络”混淆),以保持连接活动状态。在使用连接之前停用定时器,在完成连接后重新启动定时器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接