当前位置:   article > 正文

使用Qt Remote Objects 编写一个简单的文件读写代理

qt remote objects

Qt Remote Objects 是一个基于进程通信的机制,让开发人员调用一个其他进程的方法就像本地调用一样。这里我写一个简单的样例,主要是能够在进程A写入数据,但实际上是进程B写入文件数据。这样子的方式,让开发者写代码就像没有网络或者管道一样。

cmake添加字段

find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets RemoteObjects)

此处引用了qt的对应模块

添加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

  1. class Node01
  2. {
  3. PROP(bool actived=false);
  4. SLOT(server_slot(bool state));
  5. SLOT(writeFile(const QString&,const QByteArray&));
  6. SIGNAL(message(const QString&));
  7. }

上述actived只是为了测试信号是否有效。

server_slot只是为了测试槽函数是否正确链接

writeFile 是真正的跨进程写文件

message 只是为了方便的显示日志

Node01Impl.cpp

文件是作为实际提供写功能的服务端代码。

按照qt的rep接口要求,自动生成的rep_Node01_source.h定义了需要实现的接口(纯虚函数)

writeFile 需要作为槽函数实现写文件功能

  1. void Node01Impl::writeFile(const QString &fileName, const QByteArray &__repc_variable_2)
  2. {
  3. auto fileP = mFiles.value(fileName);
  4. if(fileP==nullptr)
  5. {
  6. fileP.reset(new QFile(fileName));
  7. mFiles.insert(fileName,fileP);
  8. }
  9. if(!fileP->isOpen())
  10. {
  11. auto ret = fileP->open(QIODevice::WriteOnly);
  12. if(!ret)
  13. {
  14. return ;
  15. }
  16. }
  17. if(__repc_variable_2.isEmpty())
  18. {
  19. fileP->close();
  20. mFiles.remove(fileName);
  21. return ;
  22. }
  23. fileP->write(__repc_variable_2);
  24. qDebug()<<" write "<<fileName <<" msg "<<__repc_variable_2;
  25. return ;
  26. }

上述代码效率不高,仅仅是为了实现测试效果,实际使用应该是单例文件管理,不去判断过多。

代码简单的实现了创建文件,在发送过来的信息是空的时候,关闭并且结束文件控制。

实际使用:

  1. 进程A,创建服务,可以理解为建立一个tcpserver,发布一个节点,提供大家功能

  1. void MainWindow::on_pushButton_2_clicked()
  2. {
  3. //注册一个服务集群,提供路由管理调用
  4. if(registry==nullptr)
  5. {
  6. registry= new QRemoteObjectRegistryHost(registerUrl,this);
  7. registry->setName("vvvv");
  8. }
  9. //创建服务,并且注册到指定的集群
  10. if(mHost==nullptr)
  11. {
  12. mHost = new QRemoteObjectHost(hostUrl,registerUrl);
  13. mHost->setName("zzc");
  14. }
  15. //创建我的服务
  16. if(mNode1==nullptr)
  17. {
  18. mNode1 = new Node01Impl(this);
  19. }
  20. mHost->enableRemoting(mNode1,"node1222");
  21. registry->enableRemoting(mNode1,"node001");
  22. }

上述代码,建立了一个服务,把之前的rep中实现的功能对象注册,也就是,如果其他进程找到了我注册对象,就可以使用它的函数。

  1. 进程B,查找服务,可以理解为tcp尝试去和服务器连接,找到之前注册的服务。并且创建他们之间的代理对象(不需要我们关心是断开了)

  1. //connect 创建一个用户节点,准备调用远端的方法
  2. if(repNode==nullptr)
  3. {
  4. //连结集群服务
  5. repNode = new QRemoteObjectNode(registerUrl, this);
  6. //repNode = new QRemoteObjectNode( this);
  7. //连结指定地址服务,上面构造如果注册节点有效,此处可以不需要
  8. repNode->connectToNode(hostUrl);
  9. repNode->setName("clientNode");
  10. //此处如果不等待,下面立即获取实力可能是会失败的
  11. repNode->waitForRegistry();
  12. }
  13. QStringList ins;
  14. ins<<" instaces :"<<repNode->instances<Node01Replica>();
  15. ui->textBrowser->append(ins.join(" "));
  16. if(nodePtr==nullptr)
  17. {
  18. //获取服务,使用服务,node001,node1222获取到的都是同一个对象,只是注册的名称不一样
  19. nodePtr.reset(repNode->acquire<Node01Replica>("node001"));
  20. auto dyn = repNode->acquireDynamic("node001");
  21. if(dyn)
  22. {
  23. connect(dyn,SIGNAL(message(const QString&)),this,SLOT(messageLog(const QString &)));
  24. qDebug()<<" dynamic get";
  25. }
  26. connect(nodePtr.data(),&Node01Replica::activedChanged,this,[this](){
  27. qDebug()<<" state changed "<<this->nodePtr->actived();
  28. ui->textBrowser->append(" state changed " +QString(this->nodePtr->actived()?" actived ":" inactived"));
  29. });
  30. }
  31. //简单测试目标节点的功能是否可用
  32. this->nodePtr->server_slot(false);

上述代码有少量测试逻辑,不影响整体流程。但是注意waitForRegistry是否需要取决于你是否会立即想调用远端的功能。因为后面我需要测试instances是否存在,所以会需要。实际测试,第一次调用这个函数,得到一个节点,第二次以后有两个(这个是正确的),所以链接建立是有延迟的。

  1. 进程B,尝试开始写文件

  1. for(int i=0;i<1000;++i)
  2. {
  3. auto msg = "message "+ QByteArray::number(i)+"\n";
  4. this->nodePtr->writeFile("./testfile.txt",msg);
  5. }
  6. this->nodePtr->writeFile("./testfile.txt","");

逻辑很简单,就是直接调用代理的函数。

测试,左边的app,按server建立服务,右边依次按connect和write to,写数据。

在左边的程序路径下,得到测试文件。

源码等待上传,使用的QT为6.3.2

源码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/184758
推荐阅读
相关标签
  

闽ICP备14008679号