SSL-Server und -Klient

Einrichten eines sicheren Remote-Objekt-Netzwerks mit QSslSockets.

Die Verschlüsselung der Kommunikation ist von entscheidender Bedeutung, wenn Sie Daten über ein Netzwerk übertragen müssen, über das Sie nicht die volle Kontrolle haben. Die beiden Anwendungen in diesem Beispiel zeigen, wie man entfernte Objekte über eine SSL-Verbindung freigibt und wie man auf sie zugreift.

Sowohl sslserver als auch sslcppclient verwenden ein benutzerdefiniertes Root-CA-Zertifikat, um die Zertifikate des jeweils anderen zu validieren, die sich alle in sslserver/cert befinden.

SSL-Server

Der sslserver ist mit Zertifikaten und einem privaten Schlüssel konfiguriert.

auto config = QSslConfiguration::defaultConfiguration(); config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));QFile certificateFile(QStringLiteral(":/sslcert/server.crt"));if (certificateFile.open(QIODevice::ReadOnly | QIODevice::Text)) config.setLocalCertificate(QSslCertificate(certificateFile.readAll(), QSsl::Pem));sonst    qFatal("Could not open certificate file");
QFile keyFile(QStringLiteral(":/sslcert/server.key"));if (keyFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QSslKey key(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); if (key.isNull())        qFatal("Key is not valid");
    config.setPrivateKey(key); } else {    qFatal("Could not open key file");
} config.setPeerVerifyMode(QSslSocket::VerifyPeer);QSslConfiguration::setDefaultConfiguration(config);

Dann wird ein QRemoteObjectHost Objekt und ein QSslServer Objekt erstellt. Das QSslServer Objekt lauscht auf Port 65511. Dann wird setHostUrl auf dem QRemoteObjectHost Objekt mit der URL des QSslServer Objekts aufgerufen.

QRemoteObjectHost host;
QSslServer server;
server.listen(QHostAddress::Any, 65511);
host.setHostUrl(server.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);

Ein Lambda wird verwendet, um das Signal errorOccurred zu behandeln, indem der Fehler an das Terminal ausgegeben wird. Ein zweites Lambda wird mit dem Signal pendingConnectionAvailable verbunden, das einen Error-Handler verbindet, und ruft addHostSideConnection auf dem Objekt QRemoteObjectHost mit dem eingehenden Socket als Argument auf, damit das Host-Objekt den Socket für die Kommunikation verwendet.

QObject::connect(&server, &QSslServer::errorOccurred, [](QSslSocket*socket, QAbstractSocket::SocketError error) {                     Q_UNUSED(socket);
                     qDebug() << "QSslServer::errorOccurred" << error;
                 });QObject::connect(&server, &QSslServer::pendingConnectionAvailable, [&server, &host]() {    qDebug() << "New connection available";
    QSslSocket *socket =  qobject_cast<QSslSocket *>(server.nextPendingConnection()); Q_ASSERT(socket);    QObject::connect(socket, &QSslSocket::errorOccurred, [](QAbstractSocket::SocketError error) {                         qDebug() << "QSslSocket::error" << error;
                     }); host.addHostSideConnection(socket); });

Schließlich wird ein MinuteTimer-Objekt erstellt und enableRemoting auf dem QRemoteObjectHost -Objekt mit dem MinuteTimer-Objekt als Argument aufgerufen, um die gemeinsame Nutzung zu ermöglichen.

MinuteTimer timer;
host.enableRemoting(&timer);

SSL-Klient

Der sslcppclient setzt das Root-CA-Zertifikat und erstellt dann ein Tester-Objekt.

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    auto config = QSslConfiguration::defaultConfiguration();
    config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
    QSslConfiguration::setDefaultConfiguration(config);

    Tester t;
    return a.exec();
}

Im Konstruktor des Testers wird ein temporäres QRemoteObjectNode Objekt erstellt, und setupConnection wird verwendet, um ein QSslSocket Objekt zu erstellen und zu konfigurieren. Ein Error-Handler wird angeschlossen, und das QSslSocket Objekt wird vom QRemoteObjectNode Objekt verwendet, indem es addClientSideConnection aufruft.

QRemoteObjectNode m_client;auto socket = setupConnection(); connect(socket, &QSslSocket::errorOccurred,socket, [](QAbstractSocket::SocketError error){    qDebug() << "QSslSocket::error" << error;
}) ; m_client.addClientSideConnection(socket);

Dann werden drei QScopedPointer, die Mitglieder der Klasse Tester sind, mit drei Replikaten des MinuteTimer verbunden, indem acquire auf das Objekt QRemoteObjectNode angewendet wird. Schließlich wird QTimer::singleShot viermal verwendet, um reset nach einer Verzögerung aufzurufen.

ptr1.reset(m_client.acquire< MinuteTimerReplica >());
ptr2.reset(m_client.acquire< MinuteTimerReplica >());
ptr3.reset(m_client.acquire< MinuteTimerReplica >());
QTimer::singleShot(0, this, &Tester::clear);
QTimer::singleShot(1, this, &Tester::clear);
QTimer::singleShot(10000, this, &Tester::clear);
QTimer::singleShot(11000, this, &Tester::clear);

Bei den ersten drei Aufrufen von Tester::clear wird geprüft, ob ein Zeiger gebunden ist, und dann zurückgesetzt, wobei jedes Mal ein anderer Zeiger verwendet wird. Der vierte Aufruf führt zum Beenden der Anwendung.

void clear() { static int i = 0; if (i == 0) {  i++; if (ptr1.isNull())            qCritical() << "Pointer 1 was not set";
        ptr1.reset(); } else if (i == 1) {  i++; if (ptr2.isNull())            qCritical() << "Pointer 2 was not set";
        ptr2.reset(); } else if (i == 2) {  i++; if (ptr3.isNull())            qCritical() << "Pointer 3 was not set";
        ptr3.reset(); } else {  qApp->quit(); } }

Beispielprojekt @ code.qt.io

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.