「Qtの基礎 - ネットワーク」の版間の差分
ナビゲーションに移動
検索に移動
(→概要) |
|||
62行目: | 62行目: | ||
return a.exec(); | return a.exec(); | ||
} | |||
</syntaxhighlight> | |||
<br> | |||
以下の例では、ダウンロード処理を実行するために専用のスレッドを作成して、メインスレッドはタイマを使用して定期的にこのダウンロード処理をトリガしている。<br> | |||
1分ごとにDownloader::downloadメソッドを呼び出し、ダウンロードが完了するとダウンロードしたコンテンツがコンソールに表示される。<br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>実際の設計では、適切なエラーハンドリングとリソース管理 (例: QThread::quitとQThread::waitを実行してスレッドを適切に終了させる処理)が必要となる。</u><br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QNetworkAccessManager> | |||
#include <QNetworkRequest> | |||
#include <QNetworkReply> | |||
#include <QThread> | |||
#include <QTimer> | |||
#include <QUrl> | |||
#include <QObject> | |||
class Downloader : public QObject { | |||
Q_OBJECT | |||
private: | |||
QNetworkAccessManager m_Manager; | |||
public: | |||
Downloader(QObject *parent = nullptr) : QObject(parent) { | |||
connect(&m_Manager, &QNetworkAccessManager::finished, this, &Downloader::onDownloadFinished); | |||
} | |||
void download(const QUrl &url) { | |||
QNetworkRequest request(url); | |||
m_Manager.get(request); | |||
} | |||
signals: | |||
void downloadFinished(const QString &result); | |||
private slots: | |||
void onDownloadFinished(QNetworkReply *reply) { | |||
if (reply->error()) { | |||
std::cerr << QString("Download error : %1").arg(reply->errorString()).toStdString() << std::endl; | |||
emit downloadFinished(reply->errorString()); | |||
} | |||
else { | |||
QString data = reply->readAll(); | |||
emit downloadFinished(data); | |||
} | |||
reply->deleteLater(); | |||
} | |||
}; | |||
int main(int argc, char *argv[]) { | |||
QCoreApplication app(argc, argv); | |||
QThread downloaderThread; | |||
Downloader downloader; | |||
downloader.moveToThread(&downloaderThread); | |||
downloaderThread.start(); | |||
QTimer timer; | |||
QObject::connect(&timer, &QTimer::timeout, [&downloader](){ | |||
downloader.download(QUrl("http://www.google.com")); | |||
}); | |||
QObject::connect(&downloader, &Downloader::downloadFinished, [](const QString &result){ | |||
std::cout << QString("Downloaded content : %1").arg(result).toStdString() << std::endl; | |||
}); | |||
// 1分ごとにダウンロード | |||
timer.start(60000); | |||
return app.exec(); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
2024年3月22日 (金) 15:41時点における版
概要
HTTPリクエスト / HTTPレスポンス (非同期)
一定のタイミングで取得
- ネットワークアクセスマネージャの設定
QNetworkAccessManager
クラスを使用して、HTTPリクエストを送信して、HTTPレスポンスを受信する。QNetworkAccessManager
クラスは非同期で動作し、QNetworkReply
クラスのオブジェクトを通じて結果を返す。
- タイマの設定
QTimer
クラスを使用して、指定した間隔ごとにスロット(関数)を実行する。- このスロット内でHTTPリクエストを発行する。
- マルチスレッドの実装
- Qtのマルチスレッド処理の方法はいくつか存在する。
- しかし、
QNetworkAccessManager
クラス自身は非同期処理を行うため、マルチスレッドを明示的に扱う必要はない。 - もし、ダウンロード処理のみを別のスレッドで行う場合は、
QThread
クラスまたはQtConcurrent
クラスを使用して、その中でQNetworkAccessManager
クラスのオブジェクトを作成および使用する。
#include <QCoreApplication>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QObject>
class Downloader : public QObject {
Q_OBJECT
private:
QNetworkAccessManager m_Manager;
QTimer m_Timer;
public:
Downloader() {
connect(&m_Timer, &QTimer::timeout, this, &Downloader::startDownload);
connect(&m_Manager, &QNetworkAccessManager::finished, this, &Downloader::downloadFinished);
m_Timer.start(60000); // 1分ごと
}
private slots:
void startDownload() {
QUrl url("https://www.google.com");
QNetworkRequest request(url);
m_Manager.get(request);
}
void downloadFinished(QNetworkReply *reply) {
if (reply->error()) {
qDebug() << "Download error:" << reply->errorString();
return;
}
QString data = reply->readAll();
qDebug() << data;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Downloader downloader;
return a.exec();
}
以下の例では、ダウンロード処理を実行するために専用のスレッドを作成して、メインスレッドはタイマを使用して定期的にこのダウンロード処理をトリガしている。
1分ごとにDownloader::downloadメソッドを呼び出し、ダウンロードが完了するとダウンロードしたコンテンツがコンソールに表示される。
※注意
実際の設計では、適切なエラーハンドリングとリソース管理 (例: QThread::quitとQThread::waitを実行してスレッドを適切に終了させる処理)が必要となる。
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QThread>
#include <QTimer>
#include <QUrl>
#include <QObject>
class Downloader : public QObject {
Q_OBJECT
private:
QNetworkAccessManager m_Manager;
public:
Downloader(QObject *parent = nullptr) : QObject(parent) {
connect(&m_Manager, &QNetworkAccessManager::finished, this, &Downloader::onDownloadFinished);
}
void download(const QUrl &url) {
QNetworkRequest request(url);
m_Manager.get(request);
}
signals:
void downloadFinished(const QString &result);
private slots:
void onDownloadFinished(QNetworkReply *reply) {
if (reply->error()) {
std::cerr << QString("Download error : %1").arg(reply->errorString()).toStdString() << std::endl;
emit downloadFinished(reply->errorString());
}
else {
QString data = reply->readAll();
emit downloadFinished(data);
}
reply->deleteLater();
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
QThread downloaderThread;
Downloader downloader;
downloader.moveToThread(&downloaderThread);
downloaderThread.start();
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&downloader](){
downloader.download(QUrl("http://www.google.com"));
});
QObject::connect(&downloader, &Downloader::downloadFinished, [](const QString &result){
std::cout << QString("Downloaded content : %1").arg(result).toStdString() << std::endl;
});
// 1分ごとにダウンロード
timer.start(60000);
return app.exec();
}
HTTPリクエスト / HTTPレスポンス (同期的)
同期的に取得 1
QNetworkAccessManager
クラスを使用してGETリクエストを送信した後、レスポンスを同期的に待機する場合、
QEventLoop
クラスを使用してレスポンスが完了するまでメインスレッドをブロックする。
HTTPレスポンスを受信した後、エラーチェックを行い、必要に応じてレスポンスを処理する。
ただし、同期的なHTTPリクエストはUIスレッドでブロックするため、長時間の処理や大量のリクエストの場合は非推奨である。
代わりに、非同期的なHTTPリクエストを使用することが推奨される。
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
QNetworkAccessManager manager;
// 同期的なGETリクエスト
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("https://www.google.com")));
// レスポンス待機
QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Success!";
qDebug() << "Response:" << reply->readAll();
}
else {
qDebug() << "Error:" << reply->errorString();
}
reply->deleteLater();
同期的に取得 2
非公式な方法ではあるが、QNetworkRequest
クラスのSynchronousRequestAttribute
アトリビューションを有効にすることで実現することもできる。
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
QNetworkAccessManager manager;
QNetworkRequest request(QUrl(QStringLiteral("https://www.google.com")));
request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
// 同期的なGETリクエスト
QNetworkReply *reply = manager.get(request);
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Success!";
qDebug() << "Response:" << reply->readAll();
}
else {
qDebug() << "Error:" << reply->errorString();
}
reply->deleteLater();
同期的に取得 (タイムアウト設定あり)
QNetworkReply
クラスのオブジェクトに対して、QNetworkAccessManager
クラスのsetTimeout
メソッドを使用する。
以下の例では、タイムアウトを3秒に設定しており、タイムアウト時にはQTimer
クラスを使用してタイムアウト処理を行っている。
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTimer>
QNetworkAccessManager manager;
// タイムアウトを3秒に設定
manager.setTransferTimeout(3000);
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://example.com")));
// タイムアウト用のタイマを設定
QTimer timeoutTimer;
timeoutTimer.setSingleShot(true);
QObject::connect(&timeoutTimer, &QTimer::timeout, [&](){reply->abort();});
timeoutTimer.start(3000); // タイムアウト時間を3秒に設定
// レスポンス待機
QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Response:" << reply->readAll();
}
else {
qDebug() << "Error:" << reply->errorString();
}
reply->deleteLater();