📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の6版が非表示)
60行目: 60行目:
   
   
     Downloader downloader;
     Downloader downloader;
    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>
<br>
==== 非同期で取得 (タイムアウト設定あり) ====
以下の例では、<code>QNetworkAccessManager</code>クラスを使用して、Webページのデータを非同期に取得して、<code>QTimer</code>クラスでタイムアウトを実装している。<br>
<code>QTimer::timeout</code>シグナルを使用して、指定した時間が経過した後に接続を中断 (<code>reply->abort()</code>) することにより、タイムアウト処理を行っている。<br>
<br>
また、<code>QNetworkReply::finished</code>シグナルを使用して、リクエストの完了を検知して、結果を出力している。<br>
<syntaxhighlight lang="c++">
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
// QNetworkAccessManagerのインスタンスを作成
QNetworkAccessManager manager;
// Webページを取得するためのリクエストを作成
QNetworkRequest request(QUrl("http://www.example.com"));
// リクエストを送信し、応答を受け取るためのQNetworkReplyオブジェクトを取得
QNetworkReply *reply = manager.get(request);
// タイマオブジェクトを生成して、3秒後にタイムアウトするように設定
QTimer timer;
timer.setSingleShot(true);
timer.start(3000); // 3秒後にタイムアウト
// タイマがタイムアウトした場合の処理を記述
QObject::connect(&timer, &QTimer::timeout, [&]() {
        if (reply->isRunning()) {
          // リクエストがまだ完了していない場合、接続を中断
          reply->abort();
          std::cerr << QString("タイムアウトしました").toStdString() << std::endl;
        }
});
// リクエストが完了した場合の処理を接続
QObject::connect(reply, &QNetworkReply::finished, [&]() {
        if (reply->error() == QNetworkReply::NoError) {
          // リクエストが成功して、エラーがない場合は成功
          QByteArray responseData = reply->readAll();
          std::cout << QString("受信データ : %1").arg(responseData).toStdString() << std::endl;
        }
        else if (reply->error() == QNetworkReply::OperationCanceledError) {
          std::cerr << QString("リクエストがキャンセルされました").toStdString() << std::endl;
        }
        else {
          std::cerr << QString("エラー : %1").arg(reply->errorString()).toStdString() << std::endl;
        }
        reply->deleteLater();
});
</syntaxhighlight>
<br>
==== 非同期で取得 (マルチスレッド) ====
以下の例では、マルチスレッドで2つの異なるWebサイト (https://www.example1.com および https://www.example2.com) とTCP/IP通信を行っている。<br>
<br>
<code>QtConcurrent::run</code>メソッドを使用して、2つの異なるWebサイトとの通信を並行して行い、<br>
接続を確立した後、各サーバにHTTP GETリクエストを送信する。<br>
<br>
また、このサンプルコードでは、以下に示すような仕様がある。<br>
* SSL証明書の検証
*: QSslSocket::VerifyPeerモードを設定して、ピア証明書の検証を有効にする。
*: onEncryptedスロットにより、ピア証明書の有効性を追加で確認している。
*: 接続を確立した場合、ピア証明書の有効性を確認する。
* ネットワークエラーとタイムアウトの処理
*: 接続タイムアウト (10秒) を設定している。
*: onErrorスロットでエラーをログに記録して、接続を切断する。
* バッファリングの実装
*: 受信したデータをバッファリングしている。
*: onReadyReadスロットにより、バッファからデータを行単位で処理する。
*: 完全なレスポンスを受信した時に接続を切断する。
<syntaxhighlight lang="c++">
// NetworkManager.hファイル
#include <QCoreApplication>
#include <QSslSocket>
#include <QSslCertificate>
#include <QtConcurrent>
#include <QFuture>
#include <QTimer>
#include <QDebug>
class NetworkManager : public QObject
{
    Q_OBJECT
private:
    QByteArray m_buffer;
public:
    explicit NetworkManager(QObject *parent = nullptr) : QObject(parent) {}
    void connectToHostEncrypted(const QString &hostName, quint16 port)
    {
      QSslSocket *socket = new QSslSocket(this);
      connect(socket, &QSslSocket::encrypted, this, &NetworkManager::onEncrypted);
      connect(socket, &QSslSocket::disconnected, this, &NetworkManager::onDisconnected);
      connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::errorOccurred),
              this, &NetworkManager::onError);
      connect(socket, &QSslSocket::readyRead, this, &NetworkManager::onReadyRead);
      connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
              this, &NetworkManager::onSslErrors);
      // Set up SSL configuration
      QSslConfiguration sslConfig = socket->sslConfiguration();
      sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer);
      socket->setSslConfiguration(sslConfig);
      // Set up timeout
      QTimer *timer = new QTimer(this);
      timer->setSingleShot(true);
      connect(timer, &QTimer::timeout, this, [=]() {
              if (socket->state() != QAbstractSocket::ConnectedState) {
                  qDebug() << "Connection timeout for" << hostName;
                  socket->abort();
              }
      });
      timer->start(10000);  // 10 seconds timeout
      socket->connectToHostEncrypted(hostName, port);
    }
private slots:
    void onEncrypted()
    {
      QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
      qDebug() << "Encrypted connection established with:" << socket->peerName();
      // Verify certificate
      QSslCertificate peerCert = socket->peerCertificate();
      if (peerCert.isNull()) {
          qDebug() << "Invalid peer certificate for" << socket->peerName();
          socket->disconnectFromHost();
          return;
      }
      // Send HTTP GET request
      QString request = "GET / HTTP/1.1\r\nHost: " + socket->peerName() + "\r\n\r\n";
      socket->write(request.toUtf8());
    }
    void onDisconnected()
    {
      QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
      qDebug() << "Disconnected from:" << socket->peerName();
      socket->deleteLater();
    }
    void onError(QAbstractSocket::SocketError socketError)
    {
      QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
      qDebug() << "Error occurred for" << socket->peerName() << ":" << socket->errorString();
      socket->disconnectFromHost();
    }
    void onReadyRead()
    {
      QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
      m_buffer.append(socket->readAll());
      // Process the buffer
      while (m_buffer.size() > 0) {
          // Find the end of a line
          int endOfLine = m_buffer.indexOf("\r\n");
          if (endOfLine == -1) {
            // We don't have a complete line yet
            break;
          }
          // Extract and process the line
          QByteArray line = m_buffer.left(endOfLine);
          m_buffer = m_buffer.mid(endOfLine + 2);
          qDebug() << "Received data from" << socket->peerName() << ":" << line;
      }
      // If we've received the entire response, disconnect
      if (m_buffer.contains("\r\n\r\n")) {
          socket->disconnectFromHost();
      }
    }
    void onSslErrors(const QList<QSslError> &errors)
    {
      QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
      qDebug() << "SSL Errors occurred for" << socket->peerName() << ":";
      for (const QSslError &error : errors) {
          qDebug() << error.errorString();
      }
      // In a production environment, you might want to handle specific errors differently
      // For demonstration purposes, we're disconnecting on any SSL error
      socket->disconnectFromHost();
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include "NetworkManager.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    NetworkManager manager;
    QFuture<void> future1 = QtConcurrent::run([&manager]() {
      manager.connectToHostEncrypted("www.example1.com", 443);
    });
    QFuture<void> future2 = QtConcurrent::run([&manager]() {
      manager.connectToHostEncrypted("www.example2.com", 443);
    });
    future1.waitForFinished();
    future2.waitForFinished();
   
   
     return a.exec();
     return a.exec();
126行目: 420行目:
<br>
<br>
==== 同期的に取得 (タイムアウト設定あり) ====
==== 同期的に取得 (タイムアウト設定あり) ====
<code>QNetworkReply</code>クラスのオブジェクトに対して、<code>QNetworkAccessManager</code>クラスの<code>setTimeout</code>メソッドを使用する。<br>
以下の例では、<code>QNetworkAccessManager</code>クラスを使用してHTTPリクエストを送信して、レスポンスを待機している。<br>
<code>QEventLoop</code><code>QTimer</code>を使用して、レスポンスを受信する、または、3秒経過するまで待機する。<br>
3秒経過してもレスポンスを受信しない場合は、タイムアウトとして処理する。<br>
<br>
<br>
以下の例では、タイムアウトを3秒に設定しており、タイムアウト時には<code>QTimer</code>クラスを使用してタイムアウト処理を行っている。<br>
この方法により、非同期APIを使用しながらも同期的な振る舞いを実現することができる。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <QNetworkAccessManager>
  #include <QNetworkAccessManager>
134行目: 430行目:
  #include <QNetworkReply>
  #include <QNetworkReply>
  #include <QTimer>
  #include <QTimer>
#include <QEventLoop>
   
   
  QNetworkAccessManager manager;
  QNetworkAccessManager manager;
QNetworkRequest request(QUrl("http://www.example.com"));
QNetworkReply *reply = manager.get(request);
   
   
  // タイムアウトを3秒に設定
  // イベントループを作成
  manager.setTransferTimeout(3000);
  QEventLoop loop;
   
   
  QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://example.com")));
  // タイマオブジェクトを生成して、3秒後にタイムアウトするように設定
QTimer timer;
timer.setSingleShot(true);
   
   
  // タイムアウト用のタイマを設定
  // タイマのタイムアウトシグナルとイベントループのquitメソッドを接続
QTimer timeoutTimer;
  QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
timeoutTimer.setSingleShot(true);
  QObject::connect(&timeoutTimer, &QTimer::timeout, [&](){reply->abort();});
timeoutTimer.start(3000); // タイムアウト時間を3秒に設定
   
   
  // レスポンス待機
  // レスポンスが完了したらイベントループを終了するように接続
QEventLoop loop;
  QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
  QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
// タイマを開始 (3秒後にタイムアウト)
timer.start(3000);
// イベントループを開始 (リクエストが完了する、または、タイムアウトするまで待機)
  loop.exec();
  loop.exec();
   
   
  if (reply->error() == QNetworkReply::NoError) {
  if (timer.isActive()) {
    qDebug() << "Response:" << reply->readAll();
    // タイマがアクティブな場合、リクエストが成功しているとする
    timer.stop(); // タイマを停止
    if (reply->error() == QNetworkReply::NoError) {
      QByteArray responseData = reply->readAll();
      std::cout << QString("Response received : %1").arg(responseData).toStdString() << std::endl;
    }
    else {
      std::cerr << QString("エラー : %1").arg(reply->errorString()).toStdString() << std::endl;
    }
  }
  }
  else {
  else {
     qDebug() << "Error:" << reply->errorString();
     // タイマが非アクティブな場合、タイムアウトが発生しているものとする
    std::cerr << QString("エラー : タイムアウト").toStdString() << std::endl;
  }
  }
   
   
  reply->deleteLater();
  reply->deleteLater();
</syntaxhighlight>
<br><br>
== POST ==
==== URLエンコード ====
POSTリクエストにてデータを送信する場合、データ内容に<code>&</code>、<code>#</code>、<code>+</code>、半角スペース等が存在する可能性があるため、URLエンコードする必要がある。<br>
<syntaxhighlight lang="c++">
QString message = "& + #";
QByteArray encoded = QUrl::toPercentEncoding(message.toUtf8());
</syntaxhighlight>
<br>
また、Content-Typeヘッダには<code>application/x-www-form-urlencoded</code>を指定する必要がある。<br>
<syntaxhighlight lang="c++">
// ContentTypeHeaderをHTTPリクエストに設定
QNetworkRequest request(QUrl("https://www.example.com"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::ContentLengthHeader, QString::number(encoded.length()));
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>