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

285 阅读13分钟

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

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

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

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

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

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

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

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

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

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

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

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

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

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

上一篇我们介绍了一条pdp消息的大概内容,和接收到pdp消息之后到分发给statelessreader处理的大概过程,这一篇我们介绍一下statelessreader如何接收这条消息

1.StatelessReader对于消息的处理

1.1类图

classDiagram
      MessageReceiver *-- StatelessReader
      ReaderListener <|-- PDPListener
      StatelessReader *-- PDPListener
      StatelessReader *-- ReaderHistory
      
      class MessageReceiver{
      		+std::unordered_map<EntityId_t, std::vector<RTPSReader*>> associated_readers_
      }
      class StatelessReader{
      		+ReaderHistory* mp_history
    			+ReaderListener* mp_listener
      }

1.MessageReceiver 有一个RTPSReader的队列

StatelessReader是RTPSReader的子类,MessageReceiver收到消息后交给RTPSReader处理

2.StatelessReader中有2个对象

ReaderHistory 和 ReaderListener,StatelessReader收到消息后,存入ReaderHistory,然后通过ReaderListener通知其他类处理

3.PDPListener是ReaderListener的子类

1.2时序图

sequenceDiagram
		participant MessageReceiver
    participant StatelessReader
    participant ReaderHistory
    participant PDPListener
    participant ExternalLocatorsProcessor					
		
		MessageReceiver ->> StatelessReader: 1.processDataMsg()
		StatelessReader ->> StatelessReader: 2.change_received()
		StatelessReader ->>ReaderHistory:3.received_change()
		StatelessReader ->>PDPListener:4.onNewCacheChangeAdded()
		PDPListener ->> ExternalLocatorsProcessor:5.filter_remote_locators()
		PDPListener ->> PDPSimple:6.assignRemoteEndpoints()			

1.StatelessReader::processDataMsg 主要干了这几件事情

check一下消息能不能被接收,能被接收的话,看一下消息之前有没有被处理过(根据sequenceNumber),更新sequenceNumber,CacheChange_t 拷贝一份,交给change_received()处理

2.change_received 的主要干了2件事情

a.将CacheChange_t 交给 ReaderHistory的函数change_received()处理 见3

b.调用PDPListener::onNewCacheChangeAdded函数 见4

3.ReaderHistory的函数change_received() 调用add_change,将CacheChange_t 加入到ReaderHistory 中去

4.PDPListener::onNewCacheChangeAdded 主要干了这几件事情

a.参数校验,将CacheChange_t 的数据读入ParticipantProxyData

b.ExternalLocatorsProcessor 的filter_remote_locators 函数

c.PDPSimple 的assignRemoteEndpoints 参数是ParticipantProxyData

5.ExternalLocatorsProcessor 的filter_remote_locators 函数 过滤 remote_locators, 保留一个新的remote_locator

6.PDPSimple 的assignRemoteEndpoints

 bool StatelessReader::processDataMsg(
         CacheChange_t* change)
 {
     assert(change);
 ​
     std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);
 ​
     //check 一下消息是不是能够被接收
     if (acceptMsgFrom(change->writerGUID, change->kind))
     {
         // Always assert liveliness on scope exit
         // wlp相关内容
         auto assert_liveliness_lambda = [&lock, this, change](void*)
                 {
                     lock.unlock(); // Avoid deadlock with LivelinessManager.
                     assert_writer_liveliness(change->writerGUID);
                 };
         std::unique_ptr<void, decltype(assert_liveliness_lambda)> p{ this, assert_liveliness_lambda };
 ​
 ------
         // Check rejection by history
         // check一下这个message之前是否被接收过
         if (!thereIsUpperRecordOf(change->writerGUID, change->sequenceNumber))
         {
             bool will_never_be_accepted = false;
             //check一下mp_history 能否装下change
             if (!mp_history->can_change_be_added_nts(change->writerGUID, change->serializedPayload.length, 0,
                     will_never_be_accepted))
             {
                 if (will_never_be_accepted)
                 {   //更新最后收到的消息number,这是为了后续统计消息的接收和缺失情况
                     update_last_notified(change->writerGUID, change->sequenceNumber);
                 }
                 return false;
             }
             //接收到不是自己reader的消息,更新最后收到的消息number,返回true
             //接收到特定reader的消息,就往下走
             if (data_filter_ && !data_filter_->is_relevant(*change, m_guid))
             {
                 update_last_notified(change->writerGUID, change->sequenceNumber);
                 return true;
             }
 ​
             // Ask the pool for a cache change
             CacheChange_t* change_to_add = nullptr;
             // 分配一个
             // change_pool 和payloadpool不是一个pool
             if (!change_pool_->reserve_cache(change_to_add))
             {
                 EPROSIMA_LOG_WARNING(RTPS_MSG_IN,
                         IDSTRING "Reached the maximum number of samples allowed by this reader's QoS. Rejecting change for reader: " <<
                         m_guid );
                 return false;
             }
 ​
             // Copy metadata to reserved change
             change_to_add->copy_not_memcpy(change);
 ​
             // Ask payload pool to copy the payload
             IPayloadPool* payload_owner = change->payload_owner();
             
             // 看一下是否是可以通过是能通过跨进程访问到
             bool is_datasharing = std::any_of(matched_writers_.begin(), matched_writers_.end(),
                             [&change](const RemoteWriterInfo_t& writer)
                             {
                                 return (writer.guid == change->writerGUID) && (writer.is_datasharing);
                             });
 ​
             if (is_datasharing)
             {
                 //We may receive the change from the listener (with owner a ReaderPool) or intraprocess (with owner a WriterPool)
                 ReaderPool* datasharing_pool = dynamic_cast<ReaderPool*>(payload_owner);
                 if (!datasharing_pool)
                 {
                     datasharing_pool = datasharing_listener_->get_pool_for_writer(change->writerGUID).get();
                 }
                 if (!datasharing_pool)
                 {
                     EPROSIMA_LOG_WARNING(RTPS_MSG_IN, IDSTRING "Problem copying DataSharing CacheChange from writer "
                             << change->writerGUID);
                     change_pool_->release_cache(change_to_add);
                     return false;
                 }
 ​
                 datasharing_pool->get_payload(change->serializedPayload, payload_owner, *change_to_add);
             }
             // 给change_to_add 分配payload
             else if (payload_pool_->get_payload(change->serializedPayload, payload_owner, *change_to_add))
             {
                 change->payload_owner(payload_owner);
             }
             else
             {
                 EPROSIMA_LOG_WARNING(RTPS_MSG_IN, IDSTRING "Problem copying CacheChange, received data is: "
                         << change->serializedPayload.length << " bytes and max size in reader "
                         << m_guid << " is "
                         << (fixed_payload_size_ > 0 ? fixed_payload_size_ : std::numeric_limits<uint32_t>::max()));
                 change_pool_->release_cache(change_to_add);
                 return false;
             }
 ​
             // Perform reception of cache change
             if (!change_received(change_to_add))
             {
                 EPROSIMA_LOG_INFO(RTPS_MSG_IN,
                         IDSTRING "MessageReceiver not add change " << change_to_add->sequenceNumber);
                 change_to_add->payload_owner()->release_payload(*change_to_add);
                 change_pool_->release_cache(change_to_add);
                 return false;
             }
         }
     }
 ​
     return true;
 }

//这个函数主要是对data消息的处理

1.check一下这个消息是不是能够被接收

2.check一下这个消息是不是被接收过,如果被接收过就不处理

3.如果没有被接收过,将change,加入到history中去(如果能够跨进程共享,则change的存储空间从共享内存中分配,如果不能进程间共享,则从其他地方分配)

4.调用change_received 见步骤2

步骤2:

 bool StatelessReader::change_received(
         CacheChange_t* change)
 {
     // Only make the change visible if there is not another with a bigger sequence number.
     // TODO Revisar si no hay que incluirlo.
     // 是不是已经收到
     if (!thereIsUpperRecordOf(change->writerGUID, change->sequenceNumber))
     {
         // Update Ownership strength.
         // 所有权强度
         if (EXCLUSIVE_OWNERSHIP_QOS == m_att.ownershipKind)
         {
             auto writer = std::find_if(matched_writers_.begin(), matched_writers_.end(),
                             [change](const RemoteWriterInfo_t& item)
                             {
                                 return item.guid == change->writerGUID;
                             });
             assert(matched_writers_.end() != writer);
             change->reader_info.writer_ownership_strength = writer->ownership_strength;
         }
         else
         {
             change->reader_info.writer_ownership_strength = std::numeric_limits<uint32_t>::max();
         }
 ​
         if (mp_history->received_change(change, 0))
         {
             auto payload_length = change->serializedPayload.length;
             auto guid = change->writerGUID;
             auto seq = change->sequenceNumber;
 ​
             Time_t::now(change->reader_info.receptionTimestamp);
             SequenceNumber_t previous_seq = update_last_notified(change->writerGUID, change->sequenceNumber);
             ++total_unread_;
             //空函数
             on_data_notify(guid, change->sourceTimestamp);
             //PDPListener
             auto listener = getListener();
             if (listener != nullptr)
             {
                 if (SequenceNumber_t{0, 0} != previous_seq)
                 {
                     assert(previous_seq < seq);
                     uint64_t tmp = (seq - previous_seq).to64long() - 1;
                     int32_t lost_samples = tmp > static_cast<uint64_t>(std::numeric_limits<int32_t>::max()) ?
                             std::numeric_limits<int32_t>::max() : static_cast<int32_t>(tmp);
                     if (0 < lost_samples) // There are lost samples.
                     {
                         //消息丢失做相关处理
                         //这儿是个空函数
                         listener->on_sample_lost(this, lost_samples);
                     }
                 }
 ​
                 // WARNING! These methods could destroy the change
                 bool notify_single = false;
                 // 当change available的时候,调用
                 // 这里将 notify_single变为true
                 listener->on_data_available(this, guid, seq, seq, notify_single);
                 if (notify_single)
                 {   
                     //NewCacheChange add
                     listener->onNewCacheChangeAdded(this, change);
                 }
             }
             //这个是多线程通知,有线程在等待新消息,通知这个线程有新消息到来,读取新消息
             new_notification_cv_.notify_all();
 ​
             // statistics callback
             on_subscribe_throughput(payload_length);
 ​
             return true;
         }
     }
 ​
     return false;
 }

statelessReader 的这个函数中很多逻辑其实没什么用

41-53行,statelessReader没有状态也不保存接收的数据,所以不存在所谓的数据丢失问题

56-59行,statelessReader没有必要调用on_data_available,这是个空函数

67行 statelessreader 也没有需要等待的线程

整体来看StatelessReader::change_received 有比较多的冗余代码,主要是干了2件事:

1.ReaderHistory::received_change 步骤3

2.调用了listener->onNewCacheChangeAdded这个函数,调用到了PDPListener的onNewCacheChangeAdded

也就是步骤4

我们看到这块其实有大量无用代码,可能为以后的代码预埋,逻辑上说其实没有必要。

步骤3:

 bool ReaderHistory::received_change(
         CacheChange_t* change,
         size_t)
 {
     return add_change(change);
 }
 ​
 bool ReaderHistory::add_change(
         CacheChange_t* a_change)
 {
    ------
     eprosima::utilities::collections::sorted_vector_insert(m_changes, a_change, fastdds::rtps::history_order_cmp);
     
    ------
     return true;
 }

将数据按照时间顺序存入ReaderHistory

步骤4:

 void PDPListener::onNewCacheChangeAdded(
         RTPSReader* reader,
         const CacheChange_t* const change_in)
 {
     CacheChange_t* change = const_cast<CacheChange_t*>(change_in);
     //远端的id
     GUID_t writer_guid = change->writerGUID;
     EPROSIMA_LOG_INFO(RTPS_PDP, "SPDP Message received from: " << change_in->writerGUID);
 ​
     // Make sure we have an instance handle (i.e GUID)
     if (change->instanceHandle == c_InstanceHandle_Unknown)
     {
         //如果没有guid,从mp_PDPReaderHistory 中移除
         if (!this->get_key(change))
         {
             EPROSIMA_LOG_WARNING(RTPS_PDP, "Problem getting the key of the change, removing");
             parent_pdp_->builtin_endpoints_->remove_from_pdp_reader_history(change);
             return;
         }
     }
 ​
     // Take GUID from instance handle
     GUID_t guid;
     iHandle2GUID(guid, change->instanceHandle);
     //如果alive 处理change的信息
     if (change->kind == ALIVE)
     {
         // Ignore announcement from own RTPSParticipant
         // 如果 change是自己的participant发出的,就不做处理将change 移除
         if (guid == parent_pdp_->getRTPSParticipant()->getGuid())
         {
             EPROSIMA_LOG_INFO(RTPS_PDP, "Message from own RTPSParticipant, removing");
             parent_pdp_->builtin_endpoints_->remove_from_pdp_reader_history(change);
             return;
         }
 ​
         // Release reader lock to avoid ABBA lock. PDP mutex should always be first.
         // Keep change information on local variables to check consistency later
         SequenceNumber_t seq_num = change->sequenceNumber;
         reader->getMutex().unlock();
         std::unique_lock<std::recursive_mutex> lock(*parent_pdp_->getMutex());
         reader->getMutex().lock();
 ​
         // If change is not consistent, it will be processed on the thread that has overriten it
         if ((ALIVE != change->kind) || (seq_num != change->sequenceNumber) || (writer_guid != change->writerGUID))
         {
             return;
         }
 ​
         // Access to temp_participant_data_ is protected by reader lock
 ​
         // Load information on temp_participant_data_
         CDRMessage_t msg(change->serializedPayload);
         temp_participant_data_.clear();
         //解析msg消息,放入temp_participant_data_
         if (temp_participant_data_.readFromCDRMessage(&msg, true, parent_pdp_->getRTPSParticipant()->network_factory(),
                 parent_pdp_->getRTPSParticipant()->has_shm_transport()))
         {
             // After correctly reading it
             change->instanceHandle = temp_participant_data_.m_key;
             guid = temp_participant_data_.m_guid;
 ​
             if (parent_pdp_->getRTPSParticipant()->is_participant_ignored(guid.guidPrefix))
             {
                 return;
             }
             // Filter locators
             const auto& pattr = parent_pdp_->getRTPSParticipant()->getAttributes();
             // 过滤
             // 一个新加的功能,将temp_participant_data_中的ip地址进行过滤
             fastdds::rtps::ExternalLocatorsProcessor::filter_remote_locators(temp_participant_data_,
                     pattr.builtin.metatraffic_external_unicast_locators, pattr.default_external_unicast_locators,
                     pattr.ignore_non_matching_locators);
 ​
             // Check if participant already exists (updated info)
             ParticipantProxyData* pdata = nullptr;
             for (ParticipantProxyData* it : parent_pdp_->participant_proxies_)
             {
                 if (guid == it->m_guid)
                 {
                     pdata = it;
                     break;
                 }
             }
             // pdata == nullptr 就是新发现的Participant,否则CHANGED_QOS_PARTICIPANT 更新信息
             auto status = (pdata == nullptr) ? ParticipantDiscoveryInfo::DISCOVERED_PARTICIPANT :
                     ParticipantDiscoveryInfo::CHANGED_QOS_PARTICIPANT;
 ​
             if (pdata == nullptr)
             {
                 // Create a new one when not found
                 pdata = parent_pdp_->createParticipantProxyData(temp_participant_data_, writer_guid);
 ​
                 reader->getMutex().unlock();
                 lock.unlock();
 ​
                 if (pdata != nullptr)
                 {
                     ------
                     RTPSParticipantListener* listener = parent_pdp_->getRTPSParticipant()->getListener();
                     if (listener != nullptr)
                     {
                         bool should_be_ignored = false;
                         {
                             std::lock_guard<std::mutex> cb_lock(parent_pdp_->callback_mtx_);
                             ParticipantDiscoveryInfo info(*pdata);
                             info.status = status;
 ​
                             // 
                             listener->onParticipantDiscovery(
                                 parent_pdp_->getRTPSParticipant()->getUserRTPSParticipant(),
                                 std::move(info),
                                 should_be_ignored);
                         }
                         if (should_be_ignored)
                         {
                             parent_pdp_->getRTPSParticipant()->ignore_participant(guid.guidPrefix);
                         }
 ​
                     }
 ​
                     // Assigning remote endpoints implies sending a DATA(p) to all matched and fixed readers, since
                     // StatelessWriter::matched_reader_add marks the entire history as unsent if the added reader's
                     // durability is bigger or equal to TRANSIENT_LOCAL_DURABILITY_QOS (TRANSIENT_LOCAL or TRANSIENT),
                     // which is the case of ENTITYID_BUILTIN_SDP_PARTICIPANT_READER (TRANSIENT_LOCAL). If a remote
                     // participant is discovered before creating the first DATA(p) change (which happens at the end of
                     // BuiltinProtocols::initBuiltinProtocols), then StatelessWriter::matched_reader_add ends up marking
                     // no changes as unsent (since the history is empty), which is OK because this can only happen if a
                     // participant is discovered in the middle of BuiltinProtocols::initBuiltinProtocols, which will
                     // create the first DATA(p) upon finishing, thus triggering the sent to all fixed and matched
                     // readers anyways.
                     parent_pdp_->assignRemoteEndpoints(pdata);
                 }
             }
             else
             {
                 pdata->updateData(temp_participant_data_);
                 pdata->isAlive = true;
                 reader->getMutex().unlock();
 ​
                 ······
 ​
                 if (parent_pdp_->updateInfoMatchesEDP())
                 {
                     parent_pdp_->mp_EDP->assignRemoteEndpoints(*pdata);
                 }
 ​
                 lock.unlock();
 ​
                 RTPSParticipantListener* listener = parent_pdp_->getRTPSParticipant()->getListener();
                 if (listener != nullptr)
                 {
                     bool should_be_ignored = false;
 ​
                     {
                         std::lock_guard<std::mutex> cb_lock(parent_pdp_->callback_mtx_);
                         ParticipantDiscoveryInfo info(*pdata);
                         info.status = status;
 ​
                         listener->onParticipantDiscovery(
                             parent_pdp_->getRTPSParticipant()->getUserRTPSParticipant(),
                             std::move(info),
                             should_be_ignored);
                     }
                     if (should_be_ignored)
                     {
                         parent_pdp_->getRTPSParticipant()->ignore_participant(temp_participant_data_.m_guid.guidPrefix);
                     }
                 }
             }
 ​
             // Take again the reader lock
             reader->getMutex().lock();
         }
     }
     else
     {
         reader->getMutex().unlock();
         if (parent_pdp_->remove_remote_participant(guid, ParticipantDiscoveryInfo::REMOVED_PARTICIPANT))
         {
             reader->getMutex().lock();
             // All changes related with this participant have been removed from history by remove_remote_participant
             return;
         }
         reader->getMutex().lock();
     }
 ​
     //Remove change form history.
     parent_pdp_->builtin_endpoints_->remove_from_pdp_reader_history(change);
 }

change 的类型有4种

ALIVE,

NOT_ALIVE_DISPOSED, //就是writer告知reader,我要下线了,你把这个消息处理一下

NOT_ALIVE_UNREGISTERED, //就是writer告知reader,我要把这个instance 注销掉

NOT_ALIVE_DISPOSED_UNREGISTERED//就是writer告知reader,我要下线你把消息处理一下,把这个instance 注销掉

如果不是ALIVE就意味着对端的Participant已经下线,调用parent_pdp_->remove_remote_participant

PDP消息本身包含了这个Participant的主要的信息,从消息中读取信息存入ParticipantProxyData 对象,读取了信息之后我们看一下,这个participant 是否已经存在,是否需要被忽略,已经存在那么更新这个Participant的信息,如果不存在新建一个ParticipantProxyData

上面函数主要做了这几件事

1.判断 change的类型是否是ALIVE,不是ALIVE表示对端的Participant已经下线,调用parent_pdp_->remove_remote_participant

是ALIVE则到步骤2

2.从change中读取信息数据,存入ParticipantProxyData

3.调用fastdds::rtps::ExternalLocatorsProcessor::filter_remote_locators 这个在第三部分介绍

4.判断这个participant 是否已经存在,如果存在更新这个Participant的ParticipantProxyData,不存在则新建ParticipantProxyData

5.调用PDPSimple 的assignRemoteEndpoints 这个会在下一篇详细介绍

主要功能就是Participant匹配后,根据Participant的信息匹配PDP中的 StatelessWriter和StatelessReader,EDP中的众多Writer和Reader,WLP中的众多Writer和Reader。

2.0一个功能彩蛋

fastdds::rtps::ExternalLocatorsProcessor::filter_remote_locators

这是fastdds 最近新增的一个功能,需要用户在程序中进行配置,metatraffic_external_unicast_locators,default_external_locators

对于这些配置的ip进行了分级。

举个例子,我们的一个房间里租了一个局域网,然后整个楼层又组了一个局域网。

那么房间中各个设备的ip是一个层级的,楼层的ip是另一个层级的。

metatraffic_external_unicast_locators,default_external_locators 中配置了ip,子网掩码,以及这个ip所在的层级。

然后我们根据这些配置对ParticipantProxyData中的ip地址进行过滤,只留下能够通信的ip地址。

还是以我们手机举例,有多个地址(可以参考车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)中3.2节),有wifi p2p地址,局域网地址,公共网地址,那么可以在这儿做设置,这样就可以过滤掉不能通信的地址。

过滤远端的ParticipantProxyData中的ip地址

 void filter_remote_locators(
         ParticipantProxyData& data,
         const ExternalLocators& metatraffic_external_locators,
         const ExternalLocators& default_external_locators,
         bool ignore_non_matching)
 {
     // 这儿是Participant自己的metatraffic_locators.unicast  
     filter_remote_locators(data.metatraffic_locators.unicast, metatraffic_external_locators, ignore_non_matching);
     // 这儿是Participant自己的default_locators.unicast  
     filter_remote_locators(data.default_locators.unicast, default_external_locators, ignore_non_matching);
 }

这里是具体的算法

 static void filter_remote_locators(
         fastrtps::ResourceLimitedVector<Locator>& locators,
         const ExternalLocators& external_locators,
         bool ignore_non_matching)
 {
     auto compare_locators = [external_locators, ignore_non_matching](const Locator& lhs, const Locator& rhs) -> bool
             {
                 return heuristic(lhs, external_locators, ignore_non_matching) <
                        heuristic(rhs, external_locators, ignore_non_matching);
             };
 ​
     /* This will sort the received locators according to the following criteria:
      * 1. Non-matching locators when not ignored. Heuristic value: 0
      * 2. Matching locators. Heuristic value: ((255ull - externality) << 16) | (cost << 8)
      * 3. Non-matching locators when ignored. Heuristic value: max_uint64_t
      *
      * The heuristic has been chosen so non-matching locators will never give a value that will be given to a matching
      * locator. Matching locators will be sorted first by highest externality, then by lowest cost.
      */
     // 从小到大排列
     std::sort(locators.begin(), locators.end(), compare_locators);
 ​
     /* Remove non-matching locators if requested to.
      * This is done by removing all locators at the end with an heuristic value of max_uint64_t.
      */
     if (ignore_non_matching)
     {
         while (!locators.empty())
         {
             uint64_t h = heuristic(locators.back(), external_locators, ignore_non_matching);
             if (std::numeric_limits<uint64_t>::max() != h)
             {
                 break;
             }
             //如果没有找到匹配的就去除
             locators.pop_back();
         }
     }
 ​
     // Check what locators to keep
     auto it = locators.begin();
 ​
     // Keep non-matching locators with an heuristic value of 0.
     if (!ignore_non_matching)
     {   
         //没有匹配的情况下,为0
         while (it != locators.end() && (0 == heuristic(*it, external_locators, ignore_non_matching)))
         {
             ++it;
         }
     }
     it不会是shm的情况,从local开始
     // Traverse external_locators in heuristic order, checking if certain heuristic value should be ignored
     // external_locators index从高到低遍历
     for (const auto& externality : external_locators)
     {
         for (const auto& cost : externality.second)
         {
             // Check if the locators on this heuristic value should be ignored
             //externality.first 是index,cost.first是cost
             uint64_t entry_heuristic = heuristic_value(externality.first, cost.first);
             auto end_it = it;
             size_t num_exactly_matched = 0;
             while (end_it != locators.end() &&
                     (entry_heuristic == heuristic(*end_it, external_locators, ignore_non_matching)))
             {
                 for (const LocatorWithMask& local_locator : cost.second)
                 {
                     if (std::equal(end_it->address, end_it->address + 16, local_locator.address))
                     {
                         // 地址相等
                         ++num_exactly_matched;
                         break;
                     }
                 }
                 ++end_it;
             }
             
             if (end_it != it)
             {
                 // There was at least one locator with this heuristic value
                 if (externality.first > 0 &&
                         num_exactly_matched == cost.second.size() &&
                         end_it != locators.end() &&
                         static_cast<size_t>(std::distance(it, end_it)) == num_exactly_matched)
                 {
                     // All locators on this heuristic were the local locators, ignore this heuristic
                     // 值一样
                     it = locators.erase(it, end_it);
                 }
                 else
                 {
                     // We should keep this locators, remove the rest and return
                     // 保持一个locator ,这个locator 的cost 或者level 有变化
                     it = locators.erase(end_it, locators.end());
                     return;
                 }
             }
         }
     }
 ​
 }
 ​
 //从大到小排列
 ExternalLocators = std::map<
     uint8_t, // externality_index
     std::map<
         uint8_t, // cost
         std::vector<LocatorWithMask> // locators with their mask
         >,
     std::greater<uint8_t> // Ordered by greater externality_index
     >;

具体算法在这儿,主要是过滤了一些无用的ip,这个过滤需要在初始化的时候进行设置,才能起效。具体如何设置,我这边没有设置过,后续做了实验之后,再把相关结果贴出来。

这一篇我们介绍一下statelessreader如何处理这条消息,下一篇我们介绍一下收到pdp消息之后,PDP如何匹配。

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

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

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

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

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

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

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

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

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

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

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

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

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

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