FastDDS 源码解析(二十四)创建User的DataReader(下)

349 阅读12分钟

第一篇 一个例子

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

第二篇fastdds的组成

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)

车载消息中间件FastDDS 源码解析(五)BuiltinProtocols(上)

车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP

车载消息中间件FastDDS 源码解析(七)BuiltinProtocols(下)WLP&TypeLookupManager

车载消息中间件FastDDS 源码解析(八)TimedEvent

车载消息中间件FastDDS 源码解析(九)Message

第三篇组网建立连接

pdp建连

车载消息中间件FastDDS 源码解析(十)发送第一条PDP消息(上)

FastDDS 源码解析(十一)发送第一条PDP消息(中)

FastDDS 源码解析(十二)发送第一条PDP消息(下)---异步发送

FastDDS 源码解析(十三)发送第一条PDP消息---跨进程发送

FastDDS 源码解析(十四)接收PDP消息(上)

FastDDS 源码解析(十五)接收PDP消息(下)

FastDDS 源码解析(十六)处理PDP消息——PDP匹配

EDP建连

FastDDS 源码解析(十七)处理PDP消息——EDP匹配

FastDDS 源码解析(十八)EDP阶段发送心跳heartbeat

FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息

FastDDS 源码解析(二十)处理acknack消息

FastDDS 源码解析(二十一)创建User的DataWriter(上)

FastDDS 源码解析(二十二)创建User的DataWriter(下)

FastDDS 源码解析(二十三)创建User的DataReader(上)

2.注册DataReader

这一篇我们介绍一下注册DataReader,为什么需要注册这个DataReader,这个注册是向EDP注册一下,这个DataReader的信息。

EDP会把这个信息发送给对端的EDP,这样对端就会知道有这个DataReader,如果远端有可以匹配的DataWriter,那么这两个

DataWriter 和 DataReader可以互相发送消息,发送heartbeat 和acknack消息,也可以发送消息。

这一篇就是介绍一下这个过程

2.1时序图

sequenceDiagram
participant DataReaderImpl
		participant RTPSParticipantImpl
		participant BuiltinProtocols
		Participant EDP
		Participant PDP 
		 
		DataReaderImpl ->> RTPSParticipantImpl:1.registerReader
		RTPSParticipantImpl ->> BuiltinProtocols:2.addLocalReader
		BuiltinProtocols ->> EDP:3.newLocalReaderProxyData
		EDP ->> PDP:4.addReaderProxyData
		EDP ->> EDP:5.pairing_reader_proxy_with_any_local_writer
		EDP ->> EDP:6.pairingReader
		EDP ->> EDPSimple:7.processLocalReaderProxyData
		BuiltinProtocols ->> WLP:8.add_local_reader

1.RTPSParticipant的registerWriter函数 调用了RTPSParticipantImpl的registerWriter来注册这个writer

RTPSParticipantImpl的registerWriter调用了BuiltinProtocols的addLocalWriter

2.BuiltinProtocols的addLocalReader主要干了2件事

a.BuiltinProtocols的newLocalReaderProxyData 见步骤3

b.调用WLP的add_local_reader。见步骤8:

3.BuiltinProtocols的newLocalWriterReaderData主要干了4件事

a.调用 PDP::addReaderProxyData 见步骤4

这儿有一个lamanda函数 init_fun,这个作为参数传递给addReaderProxyData

b.调用 pairing_reader_proxy_with_any_local_writer,与本地的writer进行匹配 见步骤5

c.调用 pairingReader 与已经知道的远端的Writer 匹配 见步骤6

d.调用 processLocalReaderProxyData 向远端的Reader发送消息 见步骤7

4.PDP的addReaderProxyData

先查找participant_proxies_,找到这个writer对应的ParticipantProxyData,在这个ParticipantProxyData中查找对应的ReaderProxyData,找到就更新ReaderProxyData

没有找到就新建一个ReaderProxyData,将ReaderProxyData信息存入ParticipantProxyData

5.查看本地的UserWriter,看一下Writer 和这个新建的reader是否匹配(reader和writer的很多qos是否一致)

如果匹配将reader加入到writer匹配的reader的队列中。这个是本地writer的匹配

6.遍历了participant_proxies_,找到其中的writer,与我们的reader进行匹配。

如果匹配将reader加入到writer匹配的reader的队列中。这个主要是远端writer的匹配。

7.主要是将reader 的信息,序列化后发送给远端

8.WLP来管理我们这个reader的liveliness信息

2.2源码

步骤1:

 bool RTPSParticipant::registerReader(
         RTPSReader* Reader,
         const TopicAttributes& topicAtt,
         const ReaderQos& rqos,
         const fastdds::rtps::ContentFilterProperty* content_filter)
 {
     return mp_impl->registerReader(Reader, topicAtt, rqos, content_filter);
 }

调用RTPSParticipantImpl的registerReader函数

 bool RTPSParticipantImpl::registerReader(
         RTPSReader* reader,
         const TopicAttributes& topicAtt,
         const ReaderQos& rqos,
         const fastdds::rtps::ContentFilterProperty* content_filter)
 {
     return this->mp_builtinProtocols->addLocalReader(reader, topicAtt, rqos, content_filter);
 }

步骤2:

 bool BuiltinProtocols::addLocalReader(
         RTPSReader* R,
         const fastrtps::TopicAttributes& topicAtt,
         const fastrtps::ReaderQos& rqos,
         const fastdds::rtps::ContentFilterProperty* content_filter)
 {
     bool ok = true;
 ​
     if (mp_PDP != nullptr)
    {
         ok = mp_PDP->getEDP()->newLocalReaderProxyData(R, topicAtt, rqos, content_filter);
 ​
         if (!ok)
        {
             EPROSIMA_LOG_WARNING(RTPS_EDP, "Failed register ReaderProxyData in EDP");
             return false;
        }
    }
     else
    {
         EPROSIMA_LOG_WARNING(RTPS_EDP, "EDP is not used in this Participant, register a Reader is impossible");
    }
 ​
     if (mp_WLP != nullptr)
    {
         ok &= mp_WLP->add_local_reader(R, rqos);
    }
 ​
     return ok;
 }

主要干了2件事:

1.BuiltinProtocols的newLocalReaderProxyData 见步骤3

2.调用WLP的add_local_reader。见步骤8:

步骤3:

 bool EDP::newLocalReaderProxyData(
         RTPSReader* reader,
         const TopicAttributes& att,
         const ReaderQos& rqos,
         const fastdds::rtps::ContentFilterProperty* content_filter)
 {
     EPROSIMA_LOG_INFO(RTPS_EDP, "Adding " << reader->getGuid().entityId << " in topic " << att.topicName);
 ​
     auto init_fun = [this, reader, &att, &rqos, content_filter](
         ReaderProxyData* rpd,
         bool updating,
         const ParticipantProxyData& participant_data)
            {
                 if (updating)
                {
                     EPROSIMA_LOG_ERROR(RTPS_EDP,
                             "Adding already existent reader " << reader->getGuid().entityId << " in topic "
                                                               << att.topicName);
                     return false;
                }
 ​
                 const NetworkFactory& network = mp_RTPSParticipant->network_factory();
                 const auto& ratt = reader->getAttributes();
 ​
                 rpd->isAlive(true);
                 rpd->m_expectsInlineQos = reader->expectsInlineQos();
                 rpd->guid(reader->getGuid());
                 rpd->key() = rpd->guid();
                 if (ratt.multicastLocatorList.empty() && ratt.unicastLocatorList.empty())
                {
                     rpd->set_locators(participant_data.default_locators);
                }
                 else
                {
                     rpd->set_multicast_locators(ratt.multicastLocatorList, network);
                     rpd->set_announced_unicast_locators(ratt.unicastLocatorList);
                     fastdds::rtps::ExternalLocatorsProcessor::add_external_locators(*rpd,
                             ratt.external_unicast_locators);
                }
                 rpd->RTPSParticipantKey() = mp_RTPSParticipant->getGuid();
                 rpd->topicName(att.getTopicName());
                 rpd->typeName(att.getTopicDataType());
                 rpd->topicKind(att.getTopicKind());
                 if (att.type_id.m_type_identifier._d() != static_cast<uint8_t>(0x00))
                {
                     rpd->type_id(att.type_id);
                }
                 if (att.type.m_type_object._d() != static_cast<uint8_t>(0x00))
                {
                     rpd->type(att.type);
                }
                 if (att.type_information.assigned())
                {
                     rpd->type_information(att.type_information);
                }
                 rpd->m_qos.setQos(rqos, true);
                 rpd->userDefinedId(ratt.getUserDefinedID());
                 if (nullptr != content_filter)
                {
                     // Check content of ContentFilterProperty.
                     if (!(0 < content_filter->content_filtered_topic_name.size() &&
                             0 < content_filter->related_topic_name.size() &&
                             0 < content_filter->filter_class_name.size() &&
                             0 < content_filter->filter_expression.size()
                            ))
                    {
                         return false;
                    }
 ​
                     rpd->content_filter(*content_filter);
                }
 ​
 #if HAVE_SECURITY
                 if (mp_RTPSParticipant->is_secure())
                {
                     rpd->security_attributes_ = ratt.security_attributes().mask();
                     rpd->plugin_security_attributes_ = ratt.security_attributes().plugin_endpoint_attributes;
                }
                 else
                {
                     rpd->security_attributes_ = 0UL;
                     rpd->plugin_security_attributes_ = 0UL;
                }
 #endif // if HAVE_SECURITY
                 if (att.auto_fill_type_information)
                {
                     // TypeInformation, TypeObject and TypeIdentifier
                     if (!att.type_information.assigned())
                    {
                         const types::TypeInformation* type_info =
                                 types::TypeObjectFactory::get_instance()->get_type_information(rpd->typeName().c_str());
                         if (type_info != nullptr)
                        {
                             rpd->type_information() = *type_info;
                        }
                    }
                }
 ​
                 if (att.auto_fill_type_object)
                {
                     bool has_type_id = true;
                     if (att.type_id.m_type_identifier._d() == static_cast<uint8_t>(0x00))
                    {
                         has_type_id = false;
                         const types::TypeIdentifier* type_id =
                                 types::TypeObjectFactory::get_instance()->get_type_identifier_trying_complete(
                             rpd->typeName().c_str());
                         if (type_id != nullptr)
                        {
                             has_type_id = true;
                             rpd->type_id().m_type_identifier = *type_id;
                        }
                    }
 ​
                     if (att.type.m_type_object._d() == static_cast<uint8_t>(0x00))
                    {
                         bool type_is_complete = has_type_id &&
                                 rpd->type_id().m_type_identifier._d() == types::EK_COMPLETE;
                         const types::TypeObject* type_obj =
                                 types::TypeObjectFactory::get_instance()->get_type_object(
                             rpd->typeName().c_str(), type_is_complete);
                         if (type_obj != nullptr)
                        {
                             rpd->type().m_type_object = *type_obj;
                        }
                    }
                }
 ​
                 return true;
            };
 ​
     //ADD IT TO THE LIST OF READERPROXYDATA
     GUID_t participant_guid;
     ReaderProxyData* reader_data = this->mp_PDP->addReaderProxyData(reader->getGuid(), participant_guid, init_fun);
     if (reader_data == nullptr)
    {
         return false;
    }
 ​
     //PAIRING
     if (this->mp_PDP->getRTPSParticipant()->should_match_local_endpoints())
    {
         pairing_reader_proxy_with_any_local_writer(participant_guid, reader_data);
    }
     pairingReader(reader, participant_guid, *reader_data);
     //DO SOME PROCESSING DEPENDING ON THE IMPLEMENTATION (SIMPLE OR STATIC)
     processLocalReaderProxyData(reader, reader_data);
     return true;
 }

主要干了4件事

1.调用 PDP::addReaderProxyData

2.调用 pairing_reader_proxy_with_any_local_writer,与本地的writer进行匹配

3.调用 pairingReader 与已经知道的远端的Writer 匹配

4.调用 processLocalWriterProxyData 向远端的Writer发送消息

步骤4:

 ReaderProxyData* PDP::addReaderProxyData(
         const GUID_t& reader_guid,
         GUID_t& participant_guid,
         std::function<bool(ReaderProxyData*, bool, const ParticipantProxyData&)> initializer_func)
 {
     EPROSIMA_LOG_INFO(RTPS_PDP, "Adding reader proxy data " << reader_guid);
     ReaderProxyData* ret_val = nullptr;
 ​
     // notify statistics module
     getRTPSParticipant()->on_entity_discovery(reader_guid, ParameterPropertyList_t());
 ​
     std::lock_guard<std::recursive_mutex> guardPDP(*this->mp_mutex);
 ​
     for (ParticipantProxyData* pit : participant_proxies_)
    {
         if (pit->m_guid.guidPrefix == reader_guid.guidPrefix)
        {
             // Copy participant data to be used outside.
             participant_guid = pit->m_guid;
 ​
             // Check that it is not already there:
             auto rpi = pit->m_readers->find(reader_guid.entityId);
 ​
             if ( rpi != pit->m_readers->end())
            {
                 ret_val = rpi->second;
 ​
                 if (!initializer_func(ret_val, true, *pit))
                {
                     return nullptr;
                }
 ​
                 RTPSParticipantListener* listener = mp_RTPSParticipant->getListener();
                 if (listener)
                {
                     ReaderDiscoveryInfo info(*ret_val);
                     info.status = ReaderDiscoveryInfo::CHANGED_QOS_READER;
                     listener->onReaderDiscovery(mp_RTPSParticipant->getUserRTPSParticipant(), std::move(info));
                     check_and_notify_type_discovery(listener, *ret_val);
                }
 ​
                 return ret_val;
            }
 ​
             // Try to take one entry from the pool
             if (reader_proxies_pool_.empty())
            {
                 size_t max_proxies = reader_proxies_pool_.max_size();
                 if (reader_proxies_number_ < max_proxies)
                {
                     // Pool is empty but limit has not been reached, so we create a new entry.
                     ++reader_proxies_number_;
                     ret_val = new ReaderProxyData(
                         mp_RTPSParticipant->getAttributes().allocation.locators.max_unicast_locators,
                         mp_RTPSParticipant->getAttributes().allocation.locators.max_multicast_locators,
                         mp_RTPSParticipant->getAttributes().allocation.data_limits,
                         mp_RTPSParticipant->getAttributes().allocation.content_filter);
                }
                 else
                {
                     EPROSIMA_LOG_WARNING(RTPS_PDP, "Maximum number of reader proxies (" << max_proxies <<
                             ") reached for participant " << mp_RTPSParticipant->getGuid() << std::endl);
                     return nullptr;
                }
            }
             else
            {
                 // Pool is not empty, use entry from pool
                 ret_val = reader_proxies_pool_.back();
                 reader_proxies_pool_.pop_back();
            }
 ​
             // Add to ParticipantProxyData
            (*pit->m_readers)[reader_guid.entityId] = ret_val;
 ​
             if (!initializer_func(ret_val, false, *pit))
            {
                 return nullptr;
            }
 ​
             RTPSParticipantListener* listener = mp_RTPSParticipant->getListener();
             if (listener)
            {
                 ReaderDiscoveryInfo info(*ret_val);
                 info.status = ReaderDiscoveryInfo::DISCOVERED_READER;
                 listener->onReaderDiscovery(mp_RTPSParticipant->getUserRTPSParticipant(), std::move(info));
                 check_and_notify_type_discovery(listener, *ret_val);
            }
 ​
             return ret_val;
        }
    }
 ​
     return nullptr;
 }

这个函数主要是为了创建ReaderProxyData的对象,配置参数等

先查找participant_proxies_,找到这个Reader对应的ParticipantProxyData,在这个ParticipantProxyData中查找对应的ReaderProxyData,找到就更新ReaderProxyData

没有找到就新建一个ReaderProxyData,将ReaderProxyData信息存入ParticipantProxyData

步骤5:

 bool EDP::pairing_reader_proxy_with_any_local_writer(
         const GUID_t& participant_guid,
         ReaderProxyData* rdata)
 {
    (void)participant_guid;
 ​
     EPROSIMA_LOG_INFO(RTPS_EDP, rdata->guid() << " in topic: "" << rdata->topicName() << """);
 ​
     mp_RTPSParticipant->forEachUserWriter([&, rdata](RTPSWriter& w) -> bool
            {
                 auto temp_writer_proxy_data = get_temporary_writer_proxies_pool().get();
                 GUID_t writerGUID = w.getGuid();
 ​
                 if (mp_PDP->lookupWriterProxyData(writerGUID, *temp_writer_proxy_data))
                {
                     MatchingFailureMask no_match_reason;
                     fastdds::dds::PolicyMask incompatible_qos;
                     bool valid = valid_matching(temp_writer_proxy_data.get(), rdata, no_match_reason, incompatible_qos);
                     const GUID_t& reader_guid = rdata->guid();
 ​
                     temp_writer_proxy_data.reset();
 ​
                     if (valid)
                    {
 #if HAVE_SECURITY
                         if (!mp_RTPSParticipant->security_manager().discovered_reader(writerGUID, participant_guid,
                         *rdata, w.getAttributes().security_attributes()))
                        {
                             EPROSIMA_LOG_ERROR(RTPS_EDP, "Security manager returns an error for writer " << writerGUID);
                        }
 #else
                         if (w.matched_reader_add(*rdata))
                        {
                             EPROSIMA_LOG_INFO(RTPS_EDP_MATCH,
                             "RP:" << rdata->guid() << " match W:" << w.getGuid() << ". RLoc:" <<
                                 rdata->remote_locators());
                             //MATCHED AND ADDED CORRECTLY:
                             if (w.getListener() != nullptr)
                            {
                                 MatchingInfo info;
                                 info.status = MATCHED_MATCHING;
                                 info.remoteEndpointGuid = reader_guid;
                                 w.getListener()->onWriterMatched(&w, info);
 ​
                                 const PublicationMatchedStatus& pub_info =
                                 update_publication_matched_status(reader_guid, writerGUID, 1);
                                 w.getListener()->onWriterMatched(&w, pub_info);
                            }
                        }
 #endif // if HAVE_SECURITY
                    }
                     else
                    {
                         if (no_match_reason.test(MatchingFailureMask::incompatible_qos) && w.getListener() != nullptr)
                        {
                             w.getListener()->on_offered_incompatible_qos(&w, incompatible_qos);
                        }
 ​
                         if (w.matched_reader_is_matched(reader_guid)
                         && w.matched_reader_remove(reader_guid))
                        {
 #if HAVE_SECURITY
                             mp_RTPSParticipant->security_manager().remove_reader(
                                 w.getGuid(), participant_guid, reader_guid);
 #endif // if HAVE_SECURITY
                             //MATCHED AND ADDED CORRECTLY:
                             if (w.getListener() != nullptr)
                            {
                                 MatchingInfo info;
                                 info.status = REMOVED_MATCHING;
                                 info.remoteEndpointGuid = reader_guid;
                                 w.getListener()->onWriterMatched(&w, info);
 ​
                                 const PublicationMatchedStatus& pub_info =
                                 update_publication_matched_status(reader_guid, writerGUID, -1);
                                 w.getListener()->onWriterMatched(&w, pub_info);
                            }
                        }
                    }
                }
                 // next iteration
                 return true;
            });
 ​
     return true;
 }

查看本地的UserWriter,调用valid_matching 看一下Writer 和这个新建的reader是否匹配(reader和writer的很多qos是否一致)

如果匹配matched_reader_add函数将reader加入到writer匹配的reader的队列中,(这块可以参考FastDDS 源码解析(十六)处理PDP消息——PDP匹配)。

步骤6:

 bool EDP::pairingReader(
         RTPSReader* R,
         const GUID_t& participant_guid,
         const ReaderProxyData& rdata)
 {
    (void)participant_guid;
 ​
     EPROSIMA_LOG_INFO(RTPS_EDP, rdata.guid() << " in topic: "" << rdata.topicName() << """);
     std::lock_guard<std::recursive_mutex> pguard(*mp_PDP->getMutex());
 ​
     ResourceLimitedVector<ParticipantProxyData*>::const_iterator pit = mp_PDP->ParticipantProxiesBegin();
     if (!this->mp_PDP->getRTPSParticipant()->should_match_local_endpoints())
    {
         pit++;
    }
 ​
     for (; pit != mp_PDP->ParticipantProxiesEnd(); ++pit)
    {
         for (auto& pair : *(*pit)->m_writers)
        {
             WriterProxyData* wdatait = pair.second;
             MatchingFailureMask no_match_reason;
             fastdds::dds::PolicyMask incompatible_qos;
             bool valid = valid_matching(&rdata, wdatait, no_match_reason, incompatible_qos);
             const GUID_t& reader_guid = R->getGuid();
             const GUID_t& writer_guid = wdatait->guid();
 ​
             if (valid)
            {
 #if HAVE_SECURITY
                 if (!mp_RTPSParticipant->security_manager().discovered_writer(R->m_guid, (*pit)->m_guid,
                         *wdatait, R->getAttributes().security_attributes()))
                {
                     EPROSIMA_LOG_ERROR(RTPS_EDP, "Security manager returns an error for reader " << reader_guid);
                }
 #else
                 if (R->matched_writer_add(*wdatait))
                {
                     EPROSIMA_LOG_INFO(RTPS_EDP_MATCH,
                             "WP:" << wdatait->guid() << " match R:" << R->getGuid() << ". RLoc:" <<
                             wdatait->remote_locators());
                     //MATCHED AND ADDED CORRECTLY:
                     if (R->getListener() != nullptr)
                    {
                         MatchingInfo info;
                         info.status = MATCHED_MATCHING;
                         info.remoteEndpointGuid = writer_guid;
                         R->getListener()->onReaderMatched(R, info);
 ​
                         const SubscriptionMatchedStatus& sub_info =
                                 update_subscription_matched_status(reader_guid, writer_guid, 1);
                         R->getListener()->onReaderMatched(R, sub_info);
                    }
                }
 #endif // if HAVE_SECURITY
            }
             else
            {
                 if (no_match_reason.test(MatchingFailureMask::incompatible_qos) && R->getListener() != nullptr)
                {
                     R->getListener()->on_requested_incompatible_qos(R, incompatible_qos);
                }
 ​
                 //EPROSIMA_LOG_INFO(RTPS_EDP,RTPS_CYAN<<"Valid Matching to writerProxy: "<<wdatait->m_guid<<RTPS_DEF<<endl);
                 if (R->matched_writer_is_matched(wdatait->guid())
                         && R->matched_writer_remove(wdatait->guid()))
                {
 #if HAVE_SECURITY
                     mp_RTPSParticipant->security_manager().remove_writer(reader_guid, participant_guid,
                             wdatait->guid());
 #endif // if HAVE_SECURITY
 ​
                     //MATCHED AND ADDED CORRECTLY:
                     if (R->getListener() != nullptr)
                    {
                         MatchingInfo info;
                         info.status = REMOVED_MATCHING;
                         info.remoteEndpointGuid = writer_guid;
                         R->getListener()->onReaderMatched(R, info);
 ​
                         const SubscriptionMatchedStatus& sub_info =
                                 update_subscription_matched_status(reader_guid, writer_guid, -1);
                         R->getListener()->onReaderMatched(R, sub_info);
                    }
                }
            }
        }
    }
     return true;
 }

这个函数主要从匹配的participant 中寻找writer,与reader进行匹配

参考FastDDS 源码解析(十五)接收PDP消息(下)

我们可以看到每个pdp中都会把匹配的Participant的信息,存入到participant_proxies_ ,本地的participant的信息,作为第一个ParticipantProxyData,存入到 participant_proxies_ ,远程的Participant的信息,也会存入到 participant_proxies_中去。

这个函数遍历了participant_proxies_,找到其中的writer,与我们的reader进行匹配。

如果匹配将reader加入到writer匹配的reader的队列中。

步骤7:

 bool EDPSimple::processLocalReaderProxyData(
         RTPSReader* local_reader,
         ReaderProxyData* rdata)
 {
     EPROSIMA_LOG_INFO(RTPS_EDP, rdata->guid().entityId);
    (void)local_reader;
 ​
     auto* writer = &subscriptions_writer_;
 ​
 #if HAVE_SECURITY
     if (local_reader->getAttributes().security_attributes().is_discovery_protected)
    {
         writer = &subscriptions_secure_writer_;
    }
 #endif // if HAVE_SECURITY
     CacheChange_t* change = nullptr;
     bool ret_val = serialize_reader_proxy_data(*rdata, *writer, true, &change);
     if (change != nullptr)
    {
         writer->second->add_change(change);
    }
     return ret_val;
 }

这个函数主要是将reader 的信息,序列化后发送给远端

subscriptions_writer_是发送者,信息是这个ReaderProxyData,这里面就是将ReaderProxyData中的信息,转化为一个CacheChange_t对象,然后调用WriterHistory的add_change函数

3.发送消息

3.1源码

可以参考FastDDS 源码解析(二十二)创建User的DataWriter(下)

3.2 消息模型

这块内容是对19篇内容的补充。我们在创建用户自己的Writer 和 Reader之后,就会通过EDP节点,将Writer和reader的信息通过EDP节点发送出去,这样用户自己的Writer和Reader之间就建立了连接,用户自己的Writer就能将消息发送给对端的Reader。

我们在上面的源码部分可以看到,完成EDP匹配后,再创建writer,那么可以直接发送,如果没有完成EDP匹配,先创建writer,那么就错过了直接发送,只能通过heartbeat 和 acknack,交互之后再发送了。

那么我们现在抓到的信息就是没有完成EDP匹配,先创建writer。

参考FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息

image-20240124153844456.png

sequenceDiagram
participant ParticipantA		
		participant ParticipantB
			
		ParticipantA ->> ParticipantB: 1.ParticipantA发送PDP组播消息(序号71的消息)
		ParticipantB ->> ParticipantA: 2.ParticipantB收到ParticipantA发送的PDP消息,马上发送一条PDP消息(序号78的消息)
		ParticipantB ->> ParticipantA: 3.ParticipantB收到ParticipantA发送的PDP消息,匹配EDP后,马上发送3条EDP heartbeat消息(序号79,80,81的消息)
		ParticipantA ->> ParticipantB: 4.ParticipantA收到ParticipantB发送的PDP消息后,马上发送PDP消息(序号85的单播消息,87的组播消息)
		ParticipantA ->> ParticipantB: 5.ParticipantA收到ParticipantB发送的PDP消息,匹配EDP后,马上发送3条EDP heartbeat消息(序号91,94,97的消息)
		ParticipantA ->> ParticipantB: 6.ParticipantA收到ParticipantB发送的EDP heartbeat消息后,马上发送acknack消息(序号100,103,107的消息)
		ParticipantB ->> ParticipantA: 7.ParticipantB收到ParticipantA发送的EDP heartbeat消息后,马上发送acknack消息(序号109,110,116的消息)
		ParticipantB ->> ParticipantA: 8.ParticipantB收到ParticipantA发送的acknack消息后,马上发送EDP消息(序号111的消息)
    ParticipantA ->> ParticipantB: 9.ParticipantA收到ParticipantB发送的acknack消息后,马上发送EDP消息(序号114的消息)

1-7可以参考FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息第19篇

8.ParticipantB收到ParticipantA发送的acknack消息(就是告诉ParticipantB,这边还有消息没有收到)后,马上发送EDP消息(序号111的消息)将用户自己Writer的信息发送出来。

9.ParticipantA收到ParticipantB发送的acknack消息(就是告诉ParticipantA,这边还有消息没有收到)后,马上发送EDP消息(序号114的消息)将用户自己Reader的信息发送出来。

如图所示:这条消息主要是SEDPSubWriter发送给SEDPSubReader的消息

image-20241213112619363.png

具体内容如下

PID_UNICAST_LOCATOR:这是这个writer的ip和端口号,我们留意一下这个端口号:7411

之前的PDP,EDP消息都是7410端口号,但是这个用户的Writer的端口号是一个7411

PID_TOPIC_NAME:Topic:Clipboard 这个item是说明这个TOPICNAME是Clipboard

PID_ENDPOINT_GUID:这个表明的是这个ENDPOINT的GUID,这是个Application-defined reader

PID_DURABILITY:TRANSIENT_LOCAL_DURABILITY_QOS 这个可以和我们之前介绍的部分对应上

PID_RELIABILITY:RELIABLE_RELIABILITY_QOS 这个表明这个writer是可靠的writer

还有一些其他的属性,不一一列举了。

截屏2024-12-13 11.31.27.png

到这儿,用户自己的writer 和 reader的信息进行了交互,writer和reader之间就能进行通信了。

第一篇 一个例子

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

第二篇fastdds的组成

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)

车载消息中间件FastDDS 源码解析(五)BuiltinProtocols(上)

车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP

车载消息中间件FastDDS 源码解析(七)BuiltinProtocols(下)WLP&TypeLookupManager

车载消息中间件FastDDS 源码解析(八)TimedEvent

车载消息中间件FastDDS 源码解析(九)Message

第三篇组网建立连接

pdp建连

车载消息中间件FastDDS 源码解析(十)发送第一条PDP消息(上)

FastDDS 源码解析(十一)发送第一条PDP消息(中)

FastDDS 源码解析(十二)发送第一条PDP消息(下)---异步发送

FastDDS 源码解析(十三)发送第一条PDP消息---跨进程发送

FastDDS 源码解析(十四)接收PDP消息(上)

FastDDS 源码解析(十五)接收PDP消息(下)

FastDDS 源码解析(十六)处理PDP消息——PDP匹配

EDP建连

FastDDS 源码解析(十七)处理PDP消息——EDP匹配

FastDDS 源码解析(十八)EDP阶段发送心跳heartbeat

FastDDS 源码解析(十九)EDP阶段处理heartbeat消息,发送acknack消息

FastDDS 源码解析(二十)处理acknack消息

FastDDS 源码解析(二十一)创建User的DataWriter(上)

FastDDS 源码解析(二十二)创建User的DataWriter(下)

FastDDS 源码解析(二十三)创建User的DataReader(上)