这篇文章上次修改于 197 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
Qt框架提供了多种Socket间的通信方式,并且提供了QRemoteObjects模块对Socket进行封装。。相比于其他RPC协议(如grpc等),使用QRemoteObjects后不同进程访问对象就如同在同一个进程中一样,可以直接调用其成员函数和成员变量,更加高效的完成进程通信的相关开发。所以,在对性能要求不高时可以直接使用QRemoteObjects这个进程通信框架。
QRemoteObjects框架中,把通信的两个进程分为Source端和Replica端,并且还有静态Acquire和动态Acquire的方式。
静态方式使用流程
静态方式大体使用流程:
创建rep用于定义通讯对象(可以理解为协议)
class CommonInterface { SIGNAL(sigMessage(const QString &msg)) //server下发消息给client SLOT(void onMessage(const QString &msg)) //server接收client的消息 }
pro中添加rep文件,可以设置分别生成和同时生成S和R端源文件
# 1. 同时生成,如同时用于同一程序不同实例见通讯 REPC_MERGED += singleton.rep # 2. 分别生成,通常用于不同程序 # S程序pro中 REPC_SOURCE += singleton.rep # R程序pro中 REPC_REPLICA += singleton.rep
Source端开启监听
以监听URL前缀区分通信socket类型:void Controller::init() { m_pHost = new QRemoteObjectHost(this); //通讯使用QTcpServer+QTcpSocket,可跨主机 //m_pHost->setHostUrl(QUrl("tcp://127.0.0.1:12324")); //通讯使用QLocalServer+QLocalSocket,同一主机 m_pHost->setHostUrl(QUrl("local:myinf")); m_pInterface = new CommonInterface(this); connect(m_pInterface, &CommonInterface::sigReceiveMsg, this, &Controller::onReceiveMsg); m_pHost->enableRemoting(m_pInterface); }
Replica端获取对象
void Car::init() { m_pRemoteNode = new QRemoteObjectNode(this); //bool isConnected = m_pRemoteNode->connectToNode(QUrl("tcp://127.0.0.1:12324")); bool isConnected = m_pRemoteNode->connectToNode(QUrl("local:myinf")); m_pInterface = std::shared_ptr<CommonInterfaceReplica>(m_pRemoteNode->acquire<CommonInterfaceReplica>()); //官方建议使用智能指针 m_pInterface->waitForSource(); if (m_pInterface->isReplicaValid()) { connect(m_pInterface.get(), &CommonInterfaceReplica::sigMessage, this, &Car::onReceiveMsg); return; } QMessageBox::critical(nullptr, "Error", "Connect to controller timeout.", "Exit"); ::exit(0); }
本地通讯方式权限问题
当使用local方式进行通讯时,在windows上发现当S端进程为以管理员权限运行时,以普通用户运行的R端程序无法连接并获取Replica。在这种环境下,我们不能直接使用QRemoteObjectHost::setHostUrl接口开启服务,需要自定义QIODevice作为其通信的载体:
m_pServer = new QLocalServer(this);
m_pServer->setSocketOptions(QLocalServer::WorldAccessOption); ///设置QLocalServer的权限
m_pHost = new QRemoteObjectHost(this);
m_pInterface = new CommonInterface(this);
connect(m_pInterface, &CommonInterface::sigReceiveMsg, this, &Controller::onReceiveMsg);
connect(m_pServer, &QLocalServer::newConnection, m_pHost,
[this]() {
m_pHost->addHostSideConnection(m_pServer->nextPendingConnection());
m_pHost->enableRemoting(m_pInterface);
});
m_pServer->listen(QString("myinf")); //注意这里不再需要协议前缀“local:”
动态方式
//TODO
没有评论
博主关闭了评论...