QtRemoteObjects WebSocket应用程序

使用非QIODevice基于的传输(QWebSocket)与QtRemoteObjects。

此示例通过WebSocket共享一个QStandardItemModel。该模型可以在wsserver应用程序的窗口中编辑,并且更改会传播到wsclient应用程序的窗口。

这是通过实现一个小型的QIODevice派生包装器,WebSocketIoDevice,为QWebSocket。

WsServer应用程序

wsserver应用程序创建一个有两列的QStandardItemModel,并将数据插入其中。

int main(int argc, char *argv[])
{
    QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
                                     "qt.remoteobjects.warning=false");
    QApplication app(argc, argv);

    const int modelSize = 100000;
    QStringList list;
    QStandardItemModel sourceModel;
    QStringList hHeaderList;
    hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing");
    sourceModel.setHorizontalHeaderLabels(hHeaderList);
    list.reserve(modelSize);
    for (int i = 0; i < modelSize; ++i) {
        QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i));
        if (i == 0)
            firstItem->appendRow(addChild(2, 2));
        QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i));
        if (i % 2 == 0)
            firstItem->setBackground(Qt::red);
        QList<QStandardItem*> row;
        row << firstItem << secondItem;
        sourceModel.invisibleRootItem()->appendRow(row);
        //sourceModel.appendRow(row);
        list << QStringLiteral("FancyTextNumber %1").arg(i);
    }

然后,它在一个绑定到8088端口的QWebSocketServer上启动,并托管数据模型。

QWebSocketServer webSockServer{QStringLiteral("WS QtRO"), QWebSocketServer::NonSecureMode};
webSockServer.listen(QHostAddress::Any, 8088);

QRemoteObjectHost hostNode;
hostNode.setHostUrl(webSockServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);

hostNode.enableRemoting(&sourceModel, QStringLiteral("RemoteModel"), roles);

处理新连接时,如果Qt编译支持SSL,则配置SSL。然后使用传入的WebSocketServer连接创建一个WebSocketIoDevice。

QObject::connect(&webSockServer, &QWebSocketServer::newConnection, &hostNode, [&hostNode, &webSockServer]{
    while (auto conn = webSockServer.nextPendingConnection()) {
#ifndef QT_NO_SSL
        // Always use secure connections when available
        QSslConfiguration sslConf;
        QFile certFile(QStringLiteral(":/sslcert/server.crt"));
        if (!certFile.open(QIODevice::ReadOnly))
            qFatal("Can't open client.crt file");
        sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});

        QFile keyFile(QStringLiteral(":/sslcert/server.key"));
        if (!keyFile.open(QIODevice::ReadOnly))
            qFatal("Can't open client.key file");
        sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa});

        sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer);
        conn->setSslConfiguration(sslConf);
        QObject::connect(conn, &QWebSocket::sslErrors, conn, &QWebSocket::deleteLater);
#endif
        QObject::connect(conn, &QWebSocket::disconnected, conn, &QWebSocket::deleteLater);
        QObject::connect(conn, &QWebSocket::errorOccurred, conn, &QWebSocket::deleteLater);
        auto ioDevice = new WebSocketIoDevice(conn);
        QObject::connect(conn, &QWebSocket::destroyed, ioDevice, &WebSocketIoDevice::deleteLater);
        hostNode.addHostSideConnection(ioDevice);
    }
});

创建一个以QStandardItemModel为模型的QTreeView。然后使用QTimer::singleShot启动多个计时器,以执行更多对模型的修改。

QTreeView view;
view.setWindowTitle(QStringLiteral("SourceView"));
view.setModel(&sourceModel);
view.show();
TimerHandler handler;
handler.model = &sourceModel;
QTimer::singleShot(5000, &handler, &TimerHandler::changeData);
QTimer::singleShot(10000, &handler, &TimerHandler::insertData);
QTimer::singleShot(11000, &handler, &TimerHandler::changeFlags);
QTimer::singleShot(12000, &handler, &TimerHandler::removeData);
QTimer::singleShot(13000, &handler, &TimerHandler::moveData);

return app.exec();

WsClient应用程序

wsclient应用程序创建一个QWebSocket和一个WebSocketIoDevice。

QScopedPointer<QWebSocket> webSocket{new QWebSocket};
WebSocketIoDevice socket(webSocket.data());

如果Qt编译支持SSL,则客户端将配置SSL。

#ifndef QT_NO_SSL
    // Always use secure connections when available
    QSslConfiguration sslConf;
    QFile certFile(QStringLiteral(":/sslcert/client.crt"));
    if (!certFile.open(QIODevice::ReadOnly))
        qFatal("Can't open client.crt file");
    sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});

    QFile keyFile(QStringLiteral(":/sslcert/client.key"));
    if (!keyFile.open(QIODevice::ReadOnly))
        qFatal("Can't open client.key file");
    sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa});

    sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer);
    webSocket->setSslConfiguration(sslConf);
#endif

然后创建一个QRemoteObjectNode,并设置为使用WebSocketIoDevice。然后连接到wsserver。

QRemoteObjectNode node;
node.addClientSideConnection(&socket);
node.setHeartbeatInterval(1000);
webSocket->open(QStringLiteral("ws://localhost:8088"));

创建一个用于显示服务器数据的QTreeView。从节点获取模型,然后将其设置为QTreeView的模型,然后显示。

QTreeView view;
view.setWindowTitle(QStringLiteral("RemoteView"));
view.resize(640,480);
QScopedPointer<QAbstractItemModelReplica> model(node.acquireModel(QStringLiteral("RemoteModel")));
view.setModel(model.data());
view.show();

return app.exec();

示例项目 @ code.qt.io

© 2024 Qt公司。本文档中的文档贡献的版权属于其各自的拥有者。本提供的文档依据自由软件基金会发布的GNU自由文档许可证版本1.3的条款进行许可。Qt及相应的标志是Qt公司在芬兰及其它国家的商标。所有其他商标均为各自所有者的财产。