13,007
回編集
185行目: | 185行目: | ||
reply->deleteLater(); | 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(); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> |