cyberRT 发现机制总结
代码目录
cyber 发现机制的代码都在cyber/service_discovery中,后面我们直接从topology_manager中去分析整个发现机制流程。
以下代码流程中非重要代码都用…替换。
发现机制初始化
bool TopologyManager::Init() {
if (init_.exchange(true)) {
return true;
}
//创建三个类型节点的manager
node_manager_ = std::make_shared<NodeManager>();
channel_manager_ = std::make_shared<ChannelManager>();
service_manager_ = std::make_shared<ServiceManager>();
CreateParticipant();
//主要是这步处理,对所有类型的manager做初始化
bool result =
InitNodeManager() && InitChannelManager() && InitServiceManager();
if (!result) {
...
}
return true;
}
TopologyManager::Init中主要干三件事,对node、channel、service这三个manager的初始化。init中创建了三个manager,node_manager_ 、channel_manager_ 、service_manager_ ,这三个manager都是继承自Manager。并且三个manager的init函数中做的东西很简单,都是调用了基类的StartDiscovery。我们看下StartDiscovery中的处理:
bool Manager::StartDiscovery(RtpsParticipant* participant) {
if (participant == nullptr) {
return false;
}
if (is_discovery_started_.exchange(true)) {
return true;
}
//这里创建的是fastRtps的pub和sub
if (!CreatePublisher(participant) || !CreateSubscriber(participant)) {
AERROR << "create publisher or subscriber failed.";
StopDiscovery();
return false;
}
return true;
}
可以看到StartDiscovery中做的处理就是创建出fastRtps的pub和sub,这里我们也可以总结出cyber内部的发现机制通信都是通过fastRtps。这里我理解直接使用fastRtps通信是为了避免自己再去实现trans local的机制。不管是同一机器内的通信,还是不同机器间的通信都使用了fastRtps方式。当然为了性能的极致化,也可以考虑同一机器内发现消息使用共享内存,但是这种的话你就要自己去实现trans local机制。确保晚加入的节点,能收到先加入节点的发现消息。
Topology的join和leave
这里只举例Join。
所有的节点join都是调用的基类方法Manager::Join,可以看下这个函数
bool Manager::Join(const RoleAttributes& attr, RoleType role,
bool need_publish) {
if (is_shutdown_.load()) {
ADEBUG << "the manager has been shut down.";
return false;
}
RETURN_VAL_IF(!((1 << role) & allowed_role_), false);
RETURN_VAL_IF(!Check(attr), false);
ChangeMsg msg;
Convert(attr, role, OperateType::OPT_JOIN, &msg);
Dispose(msg);
if (need_publish) {
return Publish(msg);
}
return true;
}
这里主要看Dispose和Publish这两个。Dispose调用的是各个子类的方法,比如channel拓扑节点变化了,就会调用ChannelManager::Dispose来通过channelManager的节点变化,看下面:
void ChannelManager::Dispose(const ChangeMsg& msg) {
if (msg.operate_type() == OperateType::OPT_JOIN) {
DisposeJoin(msg);
} else {
DisposeLeave(msg);
}
Notify(msg);
}
Dispose会根据这个节点是join还是leave来调用子类的DisposeJoin或者DisposeLeave方法,目的就是更新各个子类manager中保存的节点关系。另外这里还会调用Notify,里面用了QT信号和槽的机制,其实就是触发了一个callback。这个callback是使用方调用TopologyManager中的AddChangeListener设置的一个callback。
再看Publish函数,这函数就是将join或者leave消息通过fastRtps消息发给所有subscribe,让所有sub都去更新拓扑节点关系。可以看下sub收到消息后的处理,收到消息的处理是Manager::OnRemoteChange:
void Manager::OnRemoteChange(const std::string& msg_str) {
if (is_shutdown_.load()) {
ADEBUG << "the manager has been shut down.";
return;
}
ChangeMsg msg;
RETURN_IF(!message::ParseFromString(msg_str, &msg));
if (IsFromSameProcess(msg)) {
return;
}
RETURN_IF(!Check(msg.role_attr()));
Dispose(msg);
}
这里的处理也很简单,主要是收到sub拓扑节点变更消息后,触发OnRemoteChange再调用Dispose 来更新自己保存的拓扑关系。
leave这里就不细说了,和join流程差不多。