QtRemoteObjects WebSockets 应用程序

使用非基于QIODevice 的传输方式(QWebSocket)与QtRemoteObjects.NET Framework 2.0。

本示例通过网络套接字共享QStandardItemModel 。可以在wsserver 应用程序的窗口中编辑模型,更改会传播到wsclient 应用程序的窗口。

要做到这一点,需要为QWebSocket 实现一个源自QIODevice 的小型封装器WebSocketIoDevice 。如果 Qt 的编译支持 SSL,则会使用 SSL。

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,则会对其进行配置。然后使用传入的 WebSocketServer 连接创建WebSocketIoDevice

QObject::connect(&webSockServer, &QWebSocketServer::newConnection, &hostNode, [&hostNode, &webSockServer]{while(autoconn=webSockServer.nextPendingConnection()) {#ifndef QT_NO_SSL // 在可用时始终使用安全连接       QSslConfigurationsslConf;        QFilecertFile(QStringLiteral(":/sslcert/server.crt"));if(!certFile.open(QIODevice::ReadOnly))            qFatal("Can't open client.crt file");
        sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});        QFilekeyFile(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);autoioDevice= newWebSocketIoDevice(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 // 在可用时始终使用安全连接   QSslConfigurationsslConf;    QFilecertFile(QStringLiteral(":/sslcert/client.crt"));if(!certFile.open(QIODevice::ReadOnly))        qFatal("Can't open client.crt file");
    sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});    QFilekeyFile(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

© 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.