赞
踩
Qt Remote Objects 是一个基于进程通信的机制,让开发人员调用一个其他进程的方法就像本地调用一样。这里我写一个简单的样例,主要是能够在进程A写入数据,但实际上是进程B写入文件数据。这样子的方式,让开发者写代码就像没有网络或者管道一样。
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets RemoteObjects)
此处引用了qt的对应模块
file(GLOB REPSOURCE APPEND "*.rep" )
#用于建立服务端,自动编译生成节点功能模板
qt6_add_repc_sources(SourceNode
${REPSOURCE}
)
#用于客户端,实际使用者,自动生成节点代理
qt6_add_repc_replicas(SourceNode
${REPSOURCE}
)
上面两个也可以合成一段cmake,qt文档里面有对应的cmake方法。
target_link_libraries(SourceNode PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
Qt6::RemoteObjects
)
Node01.rep
- class Node01
- {
- PROP(bool actived=false);
- SLOT(server_slot(bool state));
- SLOT(writeFile(const QString&,const QByteArray&));
- SIGNAL(message(const QString&));
- }
上述actived只是为了测试信号是否有效。
server_slot只是为了测试槽函数是否正确链接
writeFile 是真正的跨进程写文件
message 只是为了方便的显示日志
文件是作为实际提供写功能的服务端代码。
按照qt的rep接口要求,自动生成的rep_Node01_source.h定义了需要实现的接口(纯虚函数)
writeFile 需要作为槽函数实现写文件功能
- void Node01Impl::writeFile(const QString &fileName, const QByteArray &__repc_variable_2)
- {
- auto fileP = mFiles.value(fileName);
- if(fileP==nullptr)
- {
- fileP.reset(new QFile(fileName));
- mFiles.insert(fileName,fileP);
- }
-
- if(!fileP->isOpen())
- {
- auto ret = fileP->open(QIODevice::WriteOnly);
- if(!ret)
- {
- return ;
- }
- }
-
- if(__repc_variable_2.isEmpty())
- {
-
- fileP->close();
- mFiles.remove(fileName);
- return ;
- }
-
-
- fileP->write(__repc_variable_2);
- qDebug()<<" write "<<fileName <<" msg "<<__repc_variable_2;
- return ;
-
- }
上述代码效率不高,仅仅是为了实现测试效果,实际使用应该是单例文件管理,不去判断过多。
代码简单的实现了创建文件,在发送过来的信息是空的时候,关闭并且结束文件控制。
实际使用:
进程A,创建服务,可以理解为建立一个tcpserver,发布一个节点,提供大家功能
- void MainWindow::on_pushButton_2_clicked()
- {
- //注册一个服务集群,提供路由管理调用
- if(registry==nullptr)
- {
- registry= new QRemoteObjectRegistryHost(registerUrl,this);
- registry->setName("vvvv");
- }
-
- //创建服务,并且注册到指定的集群
- if(mHost==nullptr)
- {
- mHost = new QRemoteObjectHost(hostUrl,registerUrl);
- mHost->setName("zzc");
- }
-
- //创建我的服务
- if(mNode1==nullptr)
- {
- mNode1 = new Node01Impl(this);
- }
- mHost->enableRemoting(mNode1,"node1222");
- registry->enableRemoting(mNode1,"node001");
-
- }
上述代码,建立了一个服务,把之前的rep中实现的功能对象注册,也就是,如果其他进程找到了我注册对象,就可以使用它的函数。
进程B,查找服务,可以理解为tcp尝试去和服务器连接,找到之前注册的服务。并且创建他们之间的代理对象(不需要我们关心是断开了)
- //connect 创建一个用户节点,准备调用远端的方法
-
- if(repNode==nullptr)
- {
- //连结集群服务
- repNode = new QRemoteObjectNode(registerUrl, this);
- //repNode = new QRemoteObjectNode( this);
- //连结指定地址服务,上面构造如果注册节点有效,此处可以不需要
- repNode->connectToNode(hostUrl);
- repNode->setName("clientNode");
- //此处如果不等待,下面立即获取实力可能是会失败的
- repNode->waitForRegistry();
- }
-
- QStringList ins;
- ins<<" instaces :"<<repNode->instances<Node01Replica>();
- ui->textBrowser->append(ins.join(" "));
- if(nodePtr==nullptr)
- {
- //获取服务,使用服务,node001,node1222获取到的都是同一个对象,只是注册的名称不一样
- nodePtr.reset(repNode->acquire<Node01Replica>("node001"));
- auto dyn = repNode->acquireDynamic("node001");
- if(dyn)
- {
- connect(dyn,SIGNAL(message(const QString&)),this,SLOT(messageLog(const QString &)));
- qDebug()<<" dynamic get";
- }
- connect(nodePtr.data(),&Node01Replica::activedChanged,this,[this](){
-
- qDebug()<<" state changed "<<this->nodePtr->actived();
- ui->textBrowser->append(" state changed " +QString(this->nodePtr->actived()?" actived ":" inactived"));
- });
-
-
- }
-
- //简单测试目标节点的功能是否可用
- this->nodePtr->server_slot(false);
上述代码有少量测试逻辑,不影响整体流程。但是注意waitForRegistry是否需要取决于你是否会立即想调用远端的功能。因为后面我需要测试instances是否存在,所以会需要。实际测试,第一次调用这个函数,得到一个节点,第二次以后有两个(这个是正确的),所以链接建立是有延迟的。
进程B,尝试开始写文件
-
- for(int i=0;i<1000;++i)
- {
- auto msg = "message "+ QByteArray::number(i)+"\n";
- this->nodePtr->writeFile("./testfile.txt",msg);
- }
- this->nodePtr->writeFile("./testfile.txt","");
逻辑很简单,就是直接调用代理的函数。
测试,左边的app,按server建立服务,右边依次按connect和write to,写数据。
在左边的程序路径下,得到测试文件。
源码等待上传,使用的QT为6.3.2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。