patterncppMinor
QNetworkReply network reply timeout helper
Viewed 0 times
helpertimeoutqnetworkreplyreplynetwork
Problem
Since Qt still does not support to set timeouts on
You can use it in a very simple fire-and-forget manner:
If the call to Google does not finish in 100ms, it is aborted. And since the
Review the code for any pitfalls, memory leaks, invalid casts and if it's generally in a good style.
QNetworkRequest objects, I wrote this little wrapper class:/**
Usage:
new QReplyTimeout(yourReply, msec);
When the timeout is reached the given reply is closed if still running
*/
class QReplyTimeout : public QObject {
Q_OBJECT
public:
QReplyTimeout(QNetworkReply* reply, const int timeout) : QObject(reply) {
Q_ASSERT(reply);
if (reply) {
QTimer::singleShot(timeout, this, SLOT(timeout()));
}
}
private slots:
void timeout() {
QNetworkReply* reply = static_cast(parent());
if (reply->isRunning()) {
reply->close();
}
}
};You can use it in a very simple fire-and-forget manner:
QNetworkAccessManager networkAccessManger;
QNetworkReply* reply = networkAccessManger.get(QNetworkRequest(QUrl("https://www.google.com")));
new QReplyTimeout(r, 100);If the call to Google does not finish in 100ms, it is aborted. And since the
QReplyTimeout class is parented to the QNetworkReply, it will be destroyed automatically.Review the code for any pitfalls, memory leaks, invalid casts and if it's generally in a good style.
Solution
Here are my thoughts:
-
It's a simple class that allocates quite a few times on the heap. You could minimize the number of implicit allocations it does. The
-
Use Qt-5 style connections, but that doesn't apply anymore in light of #1 above.
-
Add a static helper method that uses this class to set a timeout on a network request. The fact that you need to allocate
-
Check if the reply is running before you set a timeout on it. Perhaps it was an incorrect/impossible request at the moment it was submitted to the manager and it was immediately finished.
-
You're not supposed to name your classes with a
The code below is portable across Qt 4 and Qt 5:
Use:
-
It's a simple class that allocates quite a few times on the heap. You could minimize the number of implicit allocations it does. The
QTimer::singleShot creates a temporary QObject instance and allocates a bunch on the heap. You can avoid it by handling a single-shot timer explicitly using timerEvent. You also avoid the need to set up any connections that way. A QObject does about two allocations when the first connection is added to it.-
Use Qt-5 style connections, but that doesn't apply anymore in light of #1 above.
-
Add a static helper method that uses this class to set a timeout on a network request. The fact that you need to allocate
ReplyTimeout is an implementation detail of sorts that could be abstracted out that way.-
Check if the reply is running before you set a timeout on it. Perhaps it was an incorrect/impossible request at the moment it was submitted to the manager and it was immediately finished.
-
You're not supposed to name your classes with a
Q prefix. It's reserved for Qt.The code below is portable across Qt 4 and Qt 5:
class ReplyTimeout : public QObject {
Q_OBJECT
QBasicTimer m_timer;
public:
ReplyTimeout(QNetworkReply* reply, const int timeout) : QObject(reply) {
Q_ASSERT(reply);
if (reply && reply->isRunning())
m_timer.start(timeout, this);
}
static void set(QNetworkReply* reply, const int timeout) {
new ReplyTimeout(reply, timeout);
}
protected:
void timerEvent(QTimerEvent * ev) {
if (!m_timer.isActive() || ev->timerId() != m_timer.timerId())
return;
auto reply = static_cast(parent());
if (reply->isRunning())
reply->close();
m_timer.stop();
}
};Use:
QNetworkAccessManager networkAccessManger;
QNetworkReply* reply =
networkAccessManger.get(QNetworkRequest(QUrl("https://www.google.com")));
ReplyTimeout::set(reply, 100);Code Snippets
class ReplyTimeout : public QObject {
Q_OBJECT
QBasicTimer m_timer;
public:
ReplyTimeout(QNetworkReply* reply, const int timeout) : QObject(reply) {
Q_ASSERT(reply);
if (reply && reply->isRunning())
m_timer.start(timeout, this);
}
static void set(QNetworkReply* reply, const int timeout) {
new ReplyTimeout(reply, timeout);
}
protected:
void timerEvent(QTimerEvent * ev) {
if (!m_timer.isActive() || ev->timerId() != m_timer.timerId())
return;
auto reply = static_cast<QNetworkReply*>(parent());
if (reply->isRunning())
reply->close();
m_timer.stop();
}
};QNetworkAccessManager networkAccessManger;
QNetworkReply* reply =
networkAccessManger.get(QNetworkRequest(QUrl("https://www.google.com")));
ReplyTimeout::set(reply, 100);Context
StackExchange Code Review Q#30031, answer score: 7
Revisions (0)
No revisions yet.