在 Qt 中使用 QNetworkAccessManager 的持久连接

Posted

技术标签:

【中文标题】在 Qt 中使用 QNetworkAccessManager 的持久连接【英文标题】:Persistent connection using QNetworkAccessManager in Qt 【发布时间】:2015-04-20 10:41:50 【问题描述】:

我正在尝试使用 Qt 在客户端和远程服务器之间保持持久连接。我的服务器端很好。我在 Qt 中做我的客户端。在这里,我将使用 QNetworkAccessManager 通过 get 方法请求服务器(QNetworkRequest 方法的一部分)。我将能够发送和接收请求。

但过了一段时间(大约 2 分钟),客户端正在通知服务器,连接已通过自动发布请求而关闭。我认为QNetworkAccessManager 正在为此连接设置超时。我想保持两端之间的持久连接。

我的方法是否正确,如果不正确,有人可以引导我走正确的道路吗?

【问题讨论】:

这个问题对我来说似乎真的很有效。如果您找到解决方案,您介意与社区分享吗?也请提供一些代码sn-p,以便SO工程师轻松帮助您。 为什么不实现发送心跳来保持连接活跃? 如果您的服务器支持 WebSockets,您可能需要查看 doc.qt.io/qt-5/qtwebsockets-index.html 以了解您的客户端和服务器之间的持久连接。 Cameron,感谢您的参考,但工程师对 QTNetwork Manager 的可能性非常重视。你有什么想法吗? @ddrive,任何链接都应该有帮助,非常感谢。 【参考方案1】:

这个问题很有趣,所以让我们做一些研究。我设置了一个具有大保活超时的 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 代码并编译自定义版本。

【讨论】:

【参考方案2】:

根据定义,我会说 2 分钟的超时连接符合持久连接的条件。我的意思是,如果它不是持久的,那么您必须在每个请求上重新连接。与其他一些软件相比,2 分钟是相当慷慨的。但它会在一段时间不活动后最终超时,这是一件好事,这不足为奇。一些软件允许更改超时期限,但根据 Pavel 的调查,在 Qt 的情况下会出现超时是硬编码的。

幸运的是,解决方案很简单,只需设置一个计时器以每 1 分钟左右发送一次心跳(只是一个虚拟请求,不要与“心跳网络”混淆)以保持连接有效。在使用连接之前停用计时器,在连接完成后重新启动计时器。

【讨论】:

以上是关于在 Qt 中使用 QNetworkAccessManager 的持久连接的主要内容,如果未能解决你的问题,请参考以下文章

如何在VS2015中使用QT

在 Visual Studio 中使用 Qt 远程对象(带有 qt 插件)

如何在 Qt5 中使用 OpenCV

在 Qt4 中使用最新的 Qt5 串口库

在ros中使用qt图形界面

在Qt中使用 Qt Chart 5.7.0