Qt 远程对象 - 外部 QIO 设备
描述 Qt 远程对象如何支持自定义 QIODevice 通道。
外部 QIO 设备
Qt 远程对象支持多种通信通道,例如 QTcpServer 和 QTcpSocket 配对。对于所需的 tcp QUrl 或 QLocalServer 和 QLocalSocket 配对的所需名称,需要的监听和连接代码都是样板代码,并由 Qt 内部处理。Qt 远程对象还支持其他类型的 QIODevice,`QRemoteObjectNode
` 类提供了额外的帮助来支持需要自定义代码的情况。
以下是一个使用 TCP/IP 的虚构示例。更真实的例子将使用 SSL 连接,这需要配置证书等。
// Create the server and listen outside of QtRO QTcpServer tcpServer; tcpServer.listen(QHostAddress(QStringLiteral("127.0.0.1")), 65213); // Create the host node. We don't need a hostUrl unless we want to take // advantage of external schemas (see next example). QRemoteObjectHost srcNode; // Make sure any connections are handed to QtRO QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode, [&srcNode, &tcpServer]() { srcNode.addHostSideConnection(tcpServer.nextPendingConnection()); });
副本侧代码需要手动连接到主机
QRemoteObjectNode repNode; QTcpSocket *socket = new QTcpSocket(&repNode); QObject::connect(socket, &QTcpSocket::connected, &repNode, [socket, &repNode]() { repNode.addClientSideConnection(socket); }); socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")), 65213);
外部模式
可以创建 QIODevice 的每一侧并调用上述的 `addClientSideConnection(QIODevice *ioDevice)
` 和 `addHostSideConnection(QIODevice *ioDevice)
`。这是完全支持的,但要求客户端知道如何建立连接或以某种方式发现这些信息。这正是注册表被设计来解决的问题。
Qt 远程对象还允许与注册表一起使用“外部模式”,这有助于连接设置。在 QRemoteObjectHost
侧,用户必须使用所需的模式设置 hostUrl。
// Use standard tcp url for the registry const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212")); // Use "exttcp" for the "external" interface const QUrl extUrl = QUrl(QStringLiteral("exttcp://127.0.0.1:65213")); // Create the server and listen outside of QtRO QTcpServer tcpServer; tcpServer.listen(QHostAddress(extUrl.host()), extUrl.port()); // We need a registry for everyone to connect to QRemoteObjectRegistryHost registry(registryUrl); // Finally, we create our host node and register "exttcp" as our schema. // We need the AllowExternalRegistration parameter to prevent the node from // setting a hostUrlInvalid error. QRemoteObjectHost srcNode(extUrl, registryUrl, QRemoteObjectHost::AllowExternalRegistration); // From now on, when we call enableRemoting() from this node, the registry // will be updated to show the Source object at extUrl.
在 副本 侧,`QRemoteObjectNode
` 需要注册一个回调以在检测到外部模式时使用。回调必须是一个 `RemoteObjectSchemaHandler
`。
// Use standard tcp url for the registry const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212")); // This time create the node connected to the registry QRemoteObjectNode repNode(registryUrl); // Create the RemoteObjectSchemaHandler callback QRemoteObjectNode::RemoteObjectSchemaHandler setupTcp = [&repNode](QUrl url) { QTcpSocket *socket = new QTcpSocket(&repNode); connect(socket, &QTcpSocket::connected, [socket, &repNode]() { repNode.addClientSideConnection(socket); }); connect(socket, &QSslSocket::errorOccurred, [socket](QAbstractSocket::SocketError error) { delete socket; }); socket->connectToHost(url.host(), url.port()); }; // Once we call registerExternalSchema, the above method will be called // whenever the registry sees an object we are interested in on "exttcp" repNode.registerExternalSchema(QStringLiteral("exttcp"), setupTcp);