FastDDS源码解析之publisher matched过程

publisher matched过程

前面分析PDP的announceParticipantState会对participant信息进行广播。发送者guid为0.1.0.c2,目的guid为0.1.0.c7。publisher和subscriber会互相广播。
当publisher接收到来自subscriber的PDP广播时,具体处理逻辑如下:

1、UDP接收线程

在createReceiverResources过程中会创建UDPChannelResource,并且会创建一个接收线程perform_listen_operation。

void UDPChannelResource::perform_listen_operation(Locator input_locator)
{
    Locator remote_locator;
    while (alive())
    {
        // Blocking receive.
        //获取 message_buffer_
        auto& msg = message_buffer();
        //阻塞接收,实际调用recvfrom
        if (!Receive(msg.buffer, msg.max_size, msg.length, remote_locator))
        {
            continue;
        }
        if (message_receiver() != nullptr)
        {
            //进入数据处理
            message_receiver()->OnDataReceived(msg.buffer, msg.length, input_locator, remote_locator);
        }
        else if (alive())
        {
            EPROSIMA_LOG_WARNING(RTPS_MSG_IN, "Received Message, but no receiver attached");
        }
    }
    message_receiver(nullptr);
}

void MessageReceiver::processCDRMsg(
        const Locator_t& source_locator,
        const Locator_t& reception_locator,
        CDRMessage_t* msg)
{
    //获取participant层的getGuid()
    GuidPrefix_t participantGuidPrefix = participant_->getGuid().guidPrefix;
        //给dest_guid_prefix_赋值
    dest_guid_prefix_ = participantGuidPrefix;

    //获取msg的头 submessageId Length flags
    if (!readSubmessageHeader(submessage, &submsgh))
    {
        return;
}
。。。。。。
    switch (submsgh.submessageId)
    {
        case DATA:
        {
            if (dest_guid_prefix_ != participantGuidPrefix)
            {
                EPROSIMA_LOG_INFO(RTPS_MSG_IN, IDSTRING "Data Submsg ignored, DST is another RTPSParticipant");
            }
            else
            {
                //将writerId设置为Unknown
                EntityId_t writerId = c_EntityId_Unknown;
                //数据处理
                valid = proc_Submsg_Data(submessage, &submsgh, writerId);
         }
}

bool MessageReceiver::proc_Submsg_Data(
        CDRMessage_t* msg,
        SubmessageHeader_t* smh,
        EntityId_t& writerID) const
{
    eprosima::shared_lock<eprosima::shared_mutex> guard(mtx_);
    //Fill flags bool values
    bool endiannessFlag = (smh->flags & BIT(0)) != 0; // true
    bool inlineQosFlag = (smh->flags & BIT(1)) != 0;  // flase
    bool dataFlag = (smh->flags & BIT(2)) != 0;       // true
    bool keyFlag = (smh->flags & BIT(3)) != 0;        // false
    //Assign message endianness
    if (endiannessFlag)
    {
        msg->msg_endian = LITTLEEND;//小端模式
    }
    else
    {
        msg->msg_endian = BIGEND;
    }

    //Extra flags don't matter now. Avoid those bytes
    msg->pos += 2;
    bool valid = true;
    int16_t octetsToInlineQos = 0; 
    valid &= CDRMessage::readInt16(msg, &octetsToInlineQos); //it should be 16 in this implementation
    //reader and writer ID
    RTPSReader* first_reader = nullptr;
    EntityId_t readerID;
    //获取msg中的dst entityId
    valid &= CDRMessage::readEntityId(msg, &readerID);
    //We ask the reader for a cachechange to store the information.
    CacheChange_t ch;
    ch.kind = ALIVE;
    ch.writerGUID.guidPrefix = source_guid_prefix_;
    valid &= CDRMessage::readEntityId(msg, &ch.writerGUID.entityId);
    //获取发送方的 entityId
    writerID = ch.writerGUID.entityId;
    //Get sequence number
    valid &= CDRMessage::readSequenceNumber(msg, &ch.sequenceNumber);

    if (!valid)
    {
        return false;
    }

    uint32_t inlineQosSize = 0;

    if (dataFlag || keyFlag)
    {
        uint32_t payload_size;
        payload_size = smh->submessageLength -
                (RTPSMESSAGE_DATA_EXTRA_INLINEQOS_SIZE + octetsToInlineQos + inlineQosSize);

        if (dataFlag)
        {
            //拷贝 msg ==> ch
            uint32_t next_pos = msg->pos + payload_size;
            if (msg->length >= next_pos && payload_size > 0)
            {
                ch.serializedPayload.data = &msg->buffer[msg->pos];
                ch.serializedPayload.length = payload_size;
                ch.serializedPayload.max_size = payload_size;
                msg->pos = next_pos;
            }
            else
            {
                return false;
            }
        }
        else if (keyFlag)
        {
            ......
        }
    }

    process_data_message_function_(readerID, ch);
    IPayloadPool* payload_pool = ch.payload_owner();
    if (payload_pool)
    {
        payload_pool->release_payload(ch);
    }
    //TODO(Ricardo) If an exception is thrown (ex, by fastcdr), these lines are not executed -> segmentation fault
    ch.serializedPayload.data = nullptr;
    ch.inline_qos.data = nullptr;

    return true;
}

process_data_message_function_在MessageReceiver构造函数中进行了赋值:

    process_data_message_function_ = std::bind(
        &MessageReceiver::process_data_message_without_security,
        this,
        std::placeholders::_1,
        std::placeholders::_2);

void MessageReceiver::process_data_message_without_security(
        const EntityId_t& reader_id,
        CacheChange_t& change)
{
    auto process_message = [&change](RTPSReader* reader)
            {
                reader->processDataMsg(&change);
            };
    //从associated_readers_中查找EntityId_t为dst Id的reader,执行process_message
    findAllReaders(reader_id, process_message);
}

2、EDP层reader、writer匹配

bool StatelessReader::processDataMsg(
        CacheChange_t* change)
{
    assert(change);
    std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);
    //writerGUID 是否为可信 guid
    if (acceptMsgFrom(change->writerGUID, change->kind))
    {
        // Check rejection by history
        //接收到该guid的writer的帧seq >= 当前帧seq,则丢弃,说明是自己0.1.0.c2发出的
        if (!thereIsUpperRecordOf(change->writerGUID, change->sequenceNumber))
        {
            bool will_never_be_accepted = false;

            // Ask the pool for a cache change
            CacheChange_t* change_to_add = nullptr;
            //分配一块CacheChange_t
            if (!change_pool_->reserve_cache(change_to_add))
            {
                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();
            //该帧是否为datasharing类型
            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);
                            });
            // is_datasharing = false
            if (is_datasharing)
            {
                ......
            }
            //拷贝 msg ==> change_to_add
            else if (payload_pool_->get_payload(change->serializedPayload, payload_owner, *change_to_add))
            {            
                change->payload_owner(payload_owner);
            }
            else
            {
                change_pool_->release_cache(change_to_add);
                return false;
            }
            //处理cache change
            if (!change_received(change_to_add))
            {
                change_to_add->payload_owner()->release_payload(*change_to_add);
                change_pool_->release_cache(change_to_add);
                return false;
            }
        }
    }
    return true;
}

void PDPListener::onNewCacheChangeAdded(
        RTPSReader* reader,
        const CacheChange_t* const change_in)
{

    CacheChange_t* change = const_cast<CacheChange_t*>(change_in);
	GUID_t writer_guid = change->writerGUID;

    GUID_t guid;
    iHandle2GUID(guid, change->instanceHandle);
    if (change->kind == ALIVE)
    {
        CDRMessage_t msg(change->serializedPayload);
        temp_participant_data_.clear();
        if (temp_participant_data_.readFromCDRMessage(&msg, true, parent_pdp_->getRTPSParticipant()->network_factory(),parent_pdp_->getRTPSParticipant()->has_shm_transport()))
        {
            ParticipantProxyData* pdata = nullptr;
            if (pdata == nullptr)
            {
                // Create a new one when not found
                pdata = parent_pdp_->createParticipantProxyData(temp_participant_data_, writer_guid);
                    parent_pdp_->assignRemoteEndpoints(pdata);
            }
}

void PDPListener::onNewCacheChangeAdded(
        RTPSReader* reader,
        const CacheChange_t* const change_in)
{
    // change_in 转为 change
    CacheChange_t* change = const_cast<CacheChange_t*>(change_in);
    //获取writer_guid,即发送者
    GUID_t writer_guid = change->writerGUID;
    GUID_t guid;
    iHandle2GUID(guid, change->instanceHandle);
    if (change->kind == ALIVE)
    {
        //获取payload
        CDRMessage_t msg(change->serializedPayload);
        temp_participant_data_.clear();
        //获取远端locator,包含 addr port
        if (temp_participant_data_.readFromCDRMessage(&msg, true, parent_pdp_->getRTPSParticipant()->network_factory(),parent_pdp_->getRTPSParticipant()->has_shm_transport()))
        {
            ParticipantProxyData* pdata = nullptr;
            if (pdata == nullptr)
            {
                // Create a new one when not found
                pdata = parent_pdp_->createParticipantProxyData(temp_participant_data_, writer_guid);
                //处理远端端点,ParticipantProxyData包含RemoteLocatorList
                parent_pdp_->assignRemoteEndpoints(pdata);
            }
        }
    }
}

后续依次调用:
PDPSimple::assignRemoteEndpoints
PDPSimple::notifyAboveRemoteEndpoints
EDPSimple::assignRemoteEndpoints
在EDPSimple::assignRemoteEndpoints中会进行:
 matched_writer_add:将writer添加到reader-> matched_writers_pool_
这里具体添加为:
0.0.3.c2 added to 0.0.3.c7 PUBLICATIONS_WRITER  PUBLICATIONS_READER
0.0.4.c2 added to 0.0.4.c7 SUBSCRIPTIONS_WRITER  SUBSCRIPTIONS_READER
0.2.0.c2 added to 0.2.0.c7 RTPSParticipant_MESSAGE_WRITER  MESSAGE_READER
 matched_reader_add:将reader添加到writer-> matched_remote_readers_
这里具体添加为:
0.0.3.c7 to 0.0.3.c2
0.0.4.c7 to 0.0.4.c2
0.2.0.c7 to 0.2.0.c2
服务发现时的打印:
在这里插入图片描述

3、publisher、subscriber匹配

在subscriber注册后会用SUBSCRIPTIONS_WRITER 0.0.4.c2 进行广播,发送给publisher 的SUBSCRIPTIONS_READER 0.0.4.c7。
同样,publisher也会周期性广播,通过PUBLICATIONS_WRITER 0.0.3.c2广播给 PUBLICATIONS_READER 0.0.3.c7。
UDP接收线程会接收广播信息,依次调用:
MessageReceiver::findAllReaders:通过EntityId查找对应的RTPSReader。
StatefulReader::processDataMsg:
StatefulReader::NotifyChanges
EDPSimpleSUBListener::onNewCacheChangeAdded
EDPBaseSUBListener::add_reader_from_change

3.1、保存对端的IP地址信息

在EDPBaseSUBListener::add_reader_from_change中,会进行以下操作:

    CDRMessage_t tempMsg(change->serializedPayload);
    //获取PDP的temp_reader_proxies_容器,用来保存remote_locators_(发送端的IP Port)
    auto temp_reader_data = edp->get_temporary_reader_proxies_pool().get();
    //从接收消息的payload中获取相关信息(发送端locator 、Topic等),保存到remote_locators_
    if (temp_reader_data->readFromCDRMessage(&tempMsg, network,
            edp->mp_RTPSParticipant->has_shm_transport()))

下一步执行,参数rdata = temp_reader_data(ReaderProxyData类型,用于接收。)
EDP::pairing_reader_proxy_with_any_local_writer

bool EDP::pairing_reader_proxy_with_any_local_writer(
        const GUID_t& participant_guid,
        ReaderProxyData* rdata)
{
    (void)participant_guid;
    //这里rdata->guid() = 0.0.1.4 topicName = "HelloWorldTopic"
    //从 mp_RTPSParticipant->m_userWriterList中取出RTPSWriter
    mp_RTPSParticipant->forEachUserWriter([&, rdata](RTPSWriter& w) -> bool
            {
                auto temp_writer_proxy_data = get_temporary_writer_proxies_pool().get();
                //这里为0.0.1.3
                GUID_t writerGUID = w.getGuid();
                //根据writerGUID从ProxyHashTable<WriterProxyData>* 中查找 key = entityId 的 WriterProxyData
                if (mp_PDP->lookupWriterProxyData(writerGUID, *temp_writer_proxy_data))
                {
                    MatchingFailureMask no_match_reason;
                    fastdds::dds::PolicyMask incompatible_qos;
                    //查看topicName是否匹配
                    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)
                    {
                        //publisher和subscriber匹配    
                        if (w.matched_reader_add(*rdata))
                        {
                            //MATCHED AND ADDED CORRECTLY:
                            if (w.getListener() != nullptr)
                            {
                                MatchingInfo info;
                                info.status = MATCHED_MATCHING;
                                info.remoteEndpointGuid = reader_guid;
                                w.getListener()->onWriterMatched(&w, info);
                                //执行匹配callback
                                const PublicationMatchedStatus& pub_info =
                                update_publication_matched_status(reader_guid, writerGUID, 1);
                                w.getListener()->onWriterMatched(&w, pub_info);
                            }
                        }
                    }
                    else
                    {
                        ......
                    }
                }
                // next iteration
                return true;
            });
    return true;
}

w.matched_reader_add(*rdata)会将reader存入:matched_remote_readers_:
StatefulWriter::matched_reader_add:

    //这里matched_local_readers_ matched_datasharing_readers_ matched_remote_readers_均为empty
    if (for_matched_readers(matched_local_readers_, matched_datasharing_readers_, matched_remote_readers_,

构建新的 ReaderProxy

    //构建新的 ReaderProxy
    rp = new ReaderProxy(m_times, part_att.allocation.locators, this);
    //将rdata中unicast、multicast 放入rp.locator_info_
    rp->start(rdata, is_datasharing_compatible_with(rdata));

用rp.locator_info_更新StatefulWriter:: locator_selector_general_中的Locators,
在RTPSWriter::send_nts过程中,会用到locator_selector_general_,从中取出对端IP Port

locator_selector_general_.locator_selector.add_entry(rp->general_locator_selector_entry());

保存入matched_remote_readers_

    matched_remote_readers_.push_back(rp);
    EPROSIMA_LOG_INFO(RTPS_WRITER, "Adding reader " << rdata.guid() << " to " << this->m_guid.entityId<< " as remote reader");


Log如下:
Publisher subscriber匹配时的打印:
Adding reader {UNICAST:[UDPv4:[172.17.0.1]:7411,UDPv4:[192.168.88.173]:7411]}01.0f.b8.a2.a7.0c.6e.15.00.00.00.00|0.0.1.4 to 0.0.1.3 as remote reader()
后面会执行w.getListener()->onWriterMatched(&w, pub_info)。

void DataWriterImpl::InnerDataWriterListener::onWriterMatched(
        RTPSWriter* /*writer*/,
        const PublicationMatchedStatus& info)
{
    data_writer_->update_publication_matched_status(info);

    StatusMask notify_status = StatusMask::publication_matched();
    DataWriterListener* listener = data_writer_->get_listener_for(notify_status);
    if (listener != nullptr)
    {
        PublicationMatchedStatus callback_status;
        if (ReturnCode_t::RETCODE_OK == data_writer_->get_publication_matched_status(callback_status))
        {
            //执行app的on_publication_matched
            listener->on_publication_matched(data_writer_->user_datawriter_, callback_status);
        }
    }
    data_writer_->user_datawriter_->get_statuscondition().get_impl()->set_status(notify_status, true);
}

  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值