SSL服务器和客户端

使用QSslSockets设置安全的远程对象网络。

当你需要通过没有完全控制权的网络传递数据时,加密通信是至关重要的。本示例中的两个应用程序展示了如何在SSL连接上共享远程对象以及如何访问它们。

在本示例中,sslserversslcppclient 均使用自定义的根CA证书来验证对方的证书,所有证书都位于 sslserver/cert 中。

SSL服务器

sslserver 已经配置了证书和私钥。

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));
else
    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);

然后它创建了一个 QRemoteObjectHost 对象和一个 QSslServer 对象。该 QSslServer 对象监听65511端口。然后调用 QRemoteObjectHost 对象的 setHostUrl,传递 QSslServer 对象的URL。

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

使用lambda处理errorOccurred信号,将错误输出到终端。另一个lambda连接到pendingConnectionAvailable信号,该信号连接一个错误处理程序,并在 QRemoteObjectHost 对象上调用 addHostSideConnection,以将传入的套接字作为参数,使主机对象使用该套接字进行通信。

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);
});

最后,创建一个 MinuteTimer 对象,并在 QRemoteObjectHost 对象上调用 enableRemoting,该对象作为参数传递,以启用其共享。

MinuteTimer timer;
host.enableRemoting(&timer);

SSL客户端

sslcppclient 中设置根CA证书,然后创建一个 Tester 对象。

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();
}

在 Tester 构造函数中,创建了一个临时的 QRemoteObjectNode 对象,并使用 setupConnection 创建并配置了一个 QSslSocket 对象。连接了一个错误处理程序,并通过调用 addClientSideConnection 在 QRemoteObjectNode 对象上使用 QSslSocket 对象。

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

然后,使用 QRemoteObjectNode 对象的 acquire,将通过连接将三个 MinuteTimer 的副本来与其 Tester 类的三个成员 QScopedPointer 连接。最后使用际QTimer::singleShot 四次调用 reset 延时。

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);

当对于第一次调用 Tester::clear 时,检查一个指针是否已绑定然后重置,每次使用不同的指针。当第四次调用时,将导致应用程序退出。

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();
    }
}

示例项目 @ code.qt.io

© 2024 Qt 公司有限公司。本文件中包含的文档贡献均为各自所有者的版权。本文件提供的文档根据免费软件基金会发布的GNU 自由文档许可证(版本 1.3)的条款进行许可。Qt及其相关标志是芬兰 及/或其他国家的Qt 公司有限公司的商标。所有其他商标均属于各自所有者。