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

343 阅读14分钟

车载消息中间件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消息(上)

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

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

1.1EDP匹配

之前几篇我们介绍了接收到PDP消息之后的pdp匹配,由于多播的存在,在pdp匹配之前,就能接收到pdp多播的消息,只是在pdp匹配之后,我们也可以发送和接收单播的消息。

下面几篇我们介绍一下EDP的匹配,在EDP匹配之前一般是不能发送和接收EDP消息的。

image-20231205170538395.png

我们可以看到EDP有这些Writer 和 Reader,那么EDP匹配就是需要让

SEDPPubWriter 知道 远端的SEDPPubReader

SEDPPubReader 知道 远端的SEDPPubWriter

SEDPSubWriter 知道 远端的SEDPSubReader

SEDPSubReader 知道 远端的SEDPSubWriter

这样EDP消息的发送只能由SEDPPubWriter 发送到远端的SEDPPubReader或者SEDPSubWriter发送到远端的SEDPSubReader。

是不能混淆的。就是SEDPSubWriter 不能给远端的SEDPPubReader发送消息。其他的也是类似。

1.2时序图

sequenceDiagram
participant PDPSimple
		participant EDPSimple
		participant StatefulReader
		participant WriterProxy
		participant StatefulWriter
		
		PDPSimple ->> EDPSimple:1.assignRemoteEndpoints
		EDPSimple ->> StatefulReader:2.matched_writer_add
		StatefulReader ->> WriterProxy:3.new
		StatefulReader ->> WriterProxy:4.start
		EDPSimple ->> StatefulWriter:5.matched_reader_add

1.EDPSimple的assignRemoteEndpoints 就是把发现的participant对应的EDP端点,加入到对应的队列中

主要是调用了2个函数

a.StatefulReader的matched_writer_add函数

调用StatefulReader对象SEDPPubReader的matched_writer_add,将远端的SEDPPubWriter放入publications_writer_的队列中

调用StatefulReader对象SEDPSubReader的matched_writer_add,将远端的SEDPSubWriter放入subscriptions_writer_的队列中

b.matched_reader_add

调用StatefulWriter对象SEDPPubWriter的matched_reader_add,将远端的SEDPPubReader放入publications_reader_的队列中

调用StatefulReader对象SEDPSubReader的matched_reader_add,将远端的SEDPSubReader放入subscriptions_reader_的队列中

2.StatefulReader的matched_writer_add,主要干了两件事

a.new 了WriterProxy,这个WriterProxy主要存储了远端的writer的信息 见3

b.调用了WriterProxy 的start函数 见4

c.配置了相关参数和设置

3.WriterProxy的初始化函数主要是初始化了 2个TimedEvent

heartbeat_response_ 心跳回复函数,就是接收到心跳之后,回复一个消息(acknack) initial_acknack_ 初始化的acknack消息

4.WriterProxy 的start函数主要是配置了一些参数,启动initial_acknack_

5.StatefulWriter的matched_reader_add

1.3源码

步骤1:

void EDPSimple::assignRemoteEndpoints(
        const ParticipantProxyData& pdata)
{
    EPROSIMA_LOG_INFO(RTPS_EDP, "New DPD received, adding remote endpoints to our SimpleEDP endpoints");
    const NetworkFactory& network = mp_RTPSParticipant->network_factory();
    uint32_t endp = pdata.m_availableBuiltinEndpoints;
    uint32_t auxendp;
    bool use_multicast_locators = !mp_PDP->getRTPSParticipant()->getAttributes().builtin.avoid_builtin_multicast ||
            pdata.metatraffic_locators.unicast.empty();

    auto temp_reader_proxy_data = get_temporary_reader_proxies_pool().get();

    temp_reader_proxy_data->clear();
    temp_reader_proxy_data->m_expectsInlineQos = false;
    temp_reader_proxy_data->guid().guidPrefix = pdata.m_guid.guidPrefix;
    temp_reader_proxy_data->set_remote_locators(pdata.metatraffic_locators, network, use_multicast_locators);
    temp_reader_proxy_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
    temp_reader_proxy_data->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;
    
    auto temp_writer_proxy_data = get_temporary_writer_proxies_pool().get();

    temp_writer_proxy_data->clear();
    //设置guidPrefix
    temp_writer_proxy_data->guid().guidPrefix = pdata.m_guid.guidPrefix;
    temp_writer_proxy_data->persistence_guid(pdata.get_persistence_guid());
    //设置远端的locator
    temp_writer_proxy_data->set_remote_locators(pdata.metatraffic_locators, network, use_multicast_locators);
    
    temp_writer_proxy_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
    temp_writer_proxy_data->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;

    auxendp = endp;
    auxendp &= DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER;
    if (auxendp != 0 && publications_reader_.first != nullptr) //Exist Pub Writer and i have pub reader
    {
        EPROSIMA_LOG_INFO(RTPS_EDP, "Adding SEDP Pub Writer to my Pub Reader");
        temp_writer_proxy_data->guid().entityId = c_EntityId_SEDPPubWriter;
        temp_writer_proxy_data->set_persistence_entity_id(c_EntityId_SEDPPubWriter);
        publications_reader_.first->matched_writer_add(*temp_writer_proxy_data);
    }
    auxendp = endp;
    auxendp &= DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR;
    if (auxendp != 0 && publications_writer_.first != nullptr) //Exist Pub Detector
    {
        EPROSIMA_LOG_INFO(RTPS_EDP, "Adding SEDP Pub Reader to my Pub Writer");
        temp_reader_proxy_data->guid().entityId = c_EntityId_SEDPPubReader;
        publications_writer_.first->matched_reader_add(*temp_reader_proxy_data);
    }
    auxendp = endp;
    auxendp &= DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER;
    if (auxendp != 0 && subscriptions_reader_.first != nullptr) //Exist Pub Announcer
    {
        EPROSIMA_LOG_INFO(RTPS_EDP, "Adding SEDP Sub Writer to my Sub Reader");
        temp_writer_proxy_data->guid().entityId = c_EntityId_SEDPSubWriter;
        temp_writer_proxy_data->set_persistence_entity_id(c_EntityId_SEDPSubWriter);
        subscriptions_reader_.first->matched_writer_add(*temp_writer_proxy_data);
    }
    auxendp = endp;
    auxendp &= DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR;
    if (auxendp != 0 && subscriptions_writer_.first != nullptr) //Exist Pub Announcer
    {
        EPROSIMA_LOG_INFO(RTPS_EDP, "Adding SEDP Sub Reader to my Sub Writer");
        temp_reader_proxy_data->guid().entityId = c_EntityId_SEDPSubReader;
        subscriptions_writer_.first->matched_reader_add(*temp_reader_proxy_data);
    }


    ------

}

//EDPSimple::assignRemoteEndpoints,就是把发现的participant对应的EDP端点,加入到对应的队列中,主要干了这几件事

1.从缓存池中取一个temp_reader_proxy_data

代码11行

2.为temp_reader_proxy_data设置参数

代码13-18行,主要是配置guid,设置远端的locator

3.通过调用StatefulReader::matched_writer_add,做端点匹配

代码34-39行

代码53-56行

4.从缓存池中取temp_writer_proxy_data

代码20行

5.为temp_reader_proxy_data设置参数

代码22-27行

6.通过调用StatefulWriter::matched_reader_add,做端点匹配

代码46-47行

代码63-64行

pdata.m_availableBuiltinEndpoints 这个参数表示的是这个pdp中有哪些 内置的writer和reader,这是个32位的数字,每位数字表示了对应的内置的writer 或者 reader有没有配置。

EDP一般有4个Endpoint 端点

分别是远端的

SEDP Pub Writer,这个函数将SEDP Pub Writer放入publications_reader_的远端队列中

SEDP Pub Reader,这个函数将SEDP Pub Writer放入publications_writer_的远端队列中

SEDP Sub Writer,这个函数将SEDP Sub Writer放入subscriptions_reader_的远端队列中

SEDP Sub Reader,这个函数将SEDP Sub Reader放入subscriptions_writer_的远端队列中

在这里再介绍一个qos:DurabilityQos

在EDP端点匹配的时候,设置了ReaderProxyData的参数

temp_reader_proxy_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS; temp_reader_proxy_data->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;

同时设置了WriterProxyData的参数

temp_writer_proxy_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS; temp_writer_proxy_data->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;

这两个参数一般是成对出现的

TRANSIENT_LOCAL_DURABILITY_QOS是DurabilityQosPolicyKind类型的,这个参数可以设置成4种数值,

typedef enum DurabilityQosPolicyKind : fastrtps::rtps::octet
{
    VOLATILE_DURABILITY_QOS,
    TRANSIENT_LOCAL_DURABILITY_QOS,
    TRANSIENT_DURABILITY_QOS,
    PERSISTENT_DURABILITY_QOS
} DurabilityQosPolicyKind_t;

这个qos表示的是系统应该怎么处理,在reader加入前的数据

什么意思哪,比如说一个writer 已经发送了一些消息,到网络上,这时候有新的reader加入,这时候,已经发送的数据是重新发还是说不管,这些需要一些处理逻辑。

VOLATILE_DURABILITY_QOS 就是表示加入之前的消息就不用管

TRANSIENT_LOCAL_DURABILITY_QOS表示一个reader加入的时候,之前的消息也会发送给reader,这个需要和RELIABLE_RELIABILITY_QOS配合使用,只有可靠传输才能发送之前的消息

TRANSIENT_DURABILITY_QOS表示一个reader加入的时候,永久存储的消息,将会发送给reader,这个也需要和RELIABLE_RELIABILITY_QOS配合使用,只有可靠传输才能发送之前的消息

PERSISTENT_DURABILITY_QOS 这个还没有实现,预埋的一个qos

步骤2:

bool StatefulReader::matched_writer_add(
        const WriterProxyData& wdata)
{
    assert(wdata.guid() != c_Guid_Unknown);
    ReaderListener* listener = nullptr;

    {
        std::unique_lock<RecursiveTimedMutex> guard(mp_mutex);

        if (!is_alive_)
        {
            return false;
        }

        listener = mp_listener;
      	//guid 前8位一样,就在同一个进程中
        bool is_same_process = RTPSDomainImpl::should_intraprocess_between(m_guid, wdata.guid());
        bool is_datasharing = !is_same_process && is_datasharing_compatible_with(wdata);
				//查找之前已经匹配的WriterProxy
        for (WriterProxy* it : matched_writers_)
        {
            if (it->guid() == wdata.guid())
            {
                EPROSIMA_LOG_INFO(RTPS_READER, "Attempting to add existing writer, updating information");
                // If Ownership strength changes then update all history instances.
                if (EXCLUSIVE_OWNERSHIP_QOS == m_att.ownershipKind &&
                        it->ownership_strength() != wdata.m_qos.m_ownershipStrength.value)
                {
                    mp_history->writer_update_its_ownership_strength_nts(
                        it->guid(), wdata.m_qos.m_ownershipStrength.value);
                }
                //更新WriterProxy
                it->update(wdata);
                if (!is_same_process)
                {
                    //如果有新的locator,就创建一个新的SenderResource(socket)
                    for (const Locator_t& locator : it->remote_locators_shrinked())
                    {
                        getRTPSParticipant()->createSenderResources(locator);
                    }
                }

                if (nullptr != listener)
                {
                    // call the listener without the lock taken
                    guard.unlock();
                    listener->on_writer_discovery(this, WriterDiscoveryInfo::CHANGED_QOS_WRITER, wdata.guid(), &wdata);
                }
                return false;
            }
        }

        // Get a writer proxy from the inactive pool (or create a new one if necessary and allowed)
        WriterProxy* wp = nullptr;
        if (matched_writers_pool_.empty())
        {
            size_t max_readers = matched_writers_pool_.max_size();
            if (getMatchedWritersSize() + matched_writers_pool_.size() < max_readers)
            {
                const RTPSParticipantAttributes& part_att = mp_RTPSParticipant->getRTPSParticipantAttributes();
                // 创建一个新的WriterProxy
                wp = new WriterProxy(this, part_att.allocation.locators, proxy_changes_config_);
            }
            else
            {
                EPROSIMA_LOG_WARNING(RTPS_READER, "Maximum number of reader proxies (" << max_readers << \
                        ") reached for writer " << m_guid);
                return false;
            }
        }
        else
        {
            //从缓存池中取一个
            wp = matched_writers_pool_.back();
            matched_writers_pool_.pop_back();
        }
				//设置一个初始的SequenceNumber
        SequenceNumber_t initial_sequence;
        add_persistence_guid(wdata.guid(), wdata.persistence_guid());
        //获取之前收到的最新的SequenceNumber
        initial_sequence = get_last_notified(wdata.guid());

        wp->start(wdata, initial_sequence, is_datasharing);
				
      	//不是同一个进程,对于新的locator,创建SenderResources,
        if (!is_same_process)
        {
            for (const Locator_t& locator : wp->remote_locators_shrinked())
            {
                getRTPSParticipant()->createSenderResources(locator);
            }
        }
				
        if (is_datasharing)
        {
            if (datasharing_listener_->add_datasharing_writer(wdata.guid(),
                    m_att.durabilityKind == VOLATILE,
                    mp_history->m_att.maximumReservedCaches))
            {
                matched_writers_.push_back(wp);
                EPROSIMA_LOG_INFO(RTPS_READER, "Writer Proxy " << wdata.guid() << " added to " << this->m_guid.entityId
                                                               << " with data sharing");
            }
            else
            {
                EPROSIMA_LOG_ERROR(RTPS_READER, "Failed to add Writer Proxy " << wdata.guid()
                                                                              << " to " << this->m_guid.entityId
                                                                              << " with data sharing.");
                {
                    // Release reader's lock to avoid deadlock when waiting for event (requiring mutex) to finish
                    guard.unlock();
                    assert(!guard.owns_lock());
                    wp->stop();
                    guard.lock();
                }
                matched_writers_pool_.push_back(wp);
                return false;
            }

            // Intraprocess manages durability itself
            if (VOLATILE == m_att.durabilityKind)
            {
                std::shared_ptr<ReaderPool> pool = datasharing_listener_->get_pool_for_writer(wp->guid());
                SequenceNumber_t last_seq = pool->get_last_read_sequence_number();
                if (SequenceNumber_t::unknown() != last_seq)
                {
                    SequenceNumberSet_t sns(last_seq + 1);
                    send_acknack(wp, sns, wp, false);
                    wp->lost_changes_update(last_seq + 1);
                }
            }
            else if (!is_same_process)
            {
                // simulate a notification to force reading of transient changes
                datasharing_listener_->notify(false);
            }
        }
        else
        {
            //matched_writers_存入writerproxy
            matched_writers_.push_back(wp);
            EPROSIMA_LOG_INFO(RTPS_READER, "Writer Proxy " << wp->guid() << " added to " << m_guid.entityId);
        }
    }
    if (liveliness_lease_duration_ < c_TimeInfinite)
    {
        auto wlp = this->mp_RTPSParticipant->wlp();
        if ( wlp != nullptr)
        {
            //sub_liveliness_manager_这个是reader和 对端点writer,保持liveness的manager
            wlp->sub_liveliness_manager_->add_writer(
                wdata.guid(),
                liveliness_kind_,
                liveliness_lease_duration_);
        }
        else
        {
            EPROSIMA_LOG_ERROR(RTPS_LIVELINESS,
                    "Finite liveliness lease duration but WLP not enabled, cannot add writer");
        }
    }

    if (nullptr != listener)
    {
        listener->on_writer_discovery(this, WriterDiscoveryInfo::DISCOVERED_WRITER, wdata.guid(), &wdata);
    }

    return true;
}

这里面还有一个参数比较关键

initial_sequence

initial_sequence = get_last_notified(wdata.guid()); 获取从这个writer最新的SequenceNumber,

SequenceNumber_t 有两个属性

int32_t high = 0;

uint32_t low = 0;

表示history中的message 编号的范围,是从low到high。

主要干了这几件事

1.如果WriterProxyData中的writer已经在matched_writers_中,则更新WriterProxy

2.如果不在matched_writers中,则新建一个WriterProxy,存入到matched_writers

3.看一下这个writer是否可以共享内存,能够共享内存的话,加入对这个writer的共享内存监听,将WriterProxy,存入到matched_writers_ 中

不能加入监听则退出,不将WriterProxy,存入到matched_writers_ 中

4.将远端的writer加入wlp进行liveness管理

SequenceNumber_t RTPSReader::get_last_notified(
        const GUID_t& guid)
{
    SequenceNumber_t ret_val;
    std::lock_guard<RecursiveTimedMutex> guard(mp_mutex);
    GUID_t guid_to_look = guid;
    auto p_guid = history_state_->persistence_guid_map.find(guid);
    if (p_guid != history_state_->persistence_guid_map.end())
    {
        guid_to_look = p_guid->second;
    }

    auto p_seq = history_state_->history_record.find(guid_to_look);
    if (p_seq != history_state_->history_record.end())
    {
        ret_val = p_seq->second;
    }

    return ret_val;
}

这个函数会获取Writer最新发过来的数据的seqnumber。

每个reader有一个history_state_,保存着guid 和 SequenceNumber_t对象的map,这个guid表示的是远端的writer的 guid,SequenceNumber_t 是表示这个远端的writer的history中有哪些消息。

SequenceNumber_t 有两个属性

int32_t high = 0;

uint32_t low = 0;

表示history中的message 编号的范围,是从low到high。

statefulwriter发送的每一个消息,都有自己的id,每发送一个消息,id++,这些消息存储在history中。statefulwriter会发送heatbeat,这些hearbeat消息中包含了自己history中消息id的上限和下限,就是消息id的范围。

步骤3:

WriterProxy::WriterProxy(
        StatefulReader* reader,
        const RemoteLocatorsAllocationAttributes& loc_alloc,
        const ResourceLimitedContainerConfig& changes_allocation)
{
    //Create Events
    ResourceEvent& event_manager = reader_->getEventResource();
    auto heartbeat_lambda = [this]() -> bool
            {
                perform_heartbeat_response();
                return false;
            };
    auto acknack_lambda = [this]() -> bool
            {
                return perform_initial_ack_nack();
            };

    heartbeat_response_ = new TimedEvent(event_manager, heartbeat_lambda, 0);
    initial_acknack_ = new TimedEvent(event_manager, acknack_lambda, 0);

    clear();
    EPROSIMA_LOG_INFO(RTPS_READER, "Writer Proxy created in reader: " << reader_->getGuid().entityId);
}

这里面初始化了2个timedevent,heartbeat_response和initial_acknack

就是收到心跳之后的回复消息和主动的初始化acknack消息

步骤4:

void WriterProxy::start(
        const WriterProxyData& attributes,
        const SequenceNumber_t& initial_sequence,
        bool is_datasharing)
{
    using fastdds::rtps::ExternalLocatorsProcessor::filter_remote_locators;

		//设置了响应时间,就是在收到EDP的heartbeat消息,之后多久会发送response 5ms
    heartbeat_response_->update_interval(reader_->getTimes().heartbeatResponseDelay);
    //设置了时间,就是在initial_acknack_启动之后多久会发送initialacknack的消息 这里面默认是70ms
    initial_acknack_->update_interval(reader_->getTimes().initialAcknackDelay);

    locators_entry_.remote_guid = attributes.guid();
    guid_as_vector_.push_back(attributes.guid());
    guid_prefix_as_vector_.push_back(attributes.guid().guidPrefix);
    persistence_guid_ = attributes.persistence_guid();
    is_alive_ = true;
    is_on_same_process_ = RTPSDomainImpl::should_intraprocess_between(reader_->getGuid(), attributes.guid());
    ownership_strength_ = attributes.m_qos.m_ownershipStrength.value;
    liveliness_kind_ = attributes.m_qos.m_liveliness.kind;
    
    locators_entry_.unicast = attributes.remote_locators().unicast;
    locators_entry_.multicast = attributes.remote_locators().multicast;
    filter_remote_locators(locators_entry_,
            reader_->getAttributes().external_unicast_locators, reader_->getAttributes().ignore_non_matching_locators);
    is_datasharing_writer_ = is_datasharing;
    state_.store(StateCode::IDLE);
    //这里面启动了timedevent,这个可以参照之前的timedevent
    initial_acknack_->restart_timer();
    loaded_from_storage(initial_sequence);
    received_at_least_one_heartbeat_ = false;
}

这个WriterProxy::start 主要设置了一些参数,设置了发送的locators

设置了heartbeat_response的响应时间,heartbeat_response这个TimedEvent会在接收到heartbear的时候启动,这个会在后续详细介绍。也就是acknack消息的发送。

设置了initial_acknack的响应时间,这个initial_acknack是主动发起的

initial_acknack_->restart_timer();就是在这儿主动发起了发送initial_acknack的消息

locators_entry中存放的就是要发送的远端的地址,后续发送消息通过这些地址发送

initial_acknack_ 的时间间隔默认是70ms,到了70ms就会执行下面的函数

bool WriterProxy::perform_initial_ack_nack()
{
    bool ret_value = false;

    StateCode expected = StateCode::IDLE;
    if (!state_.compare_exchange_strong(expected, StateCode::BUSY))
    {
        // Stopped from another thread -> abort
        return ret_value;
    }

    if (!is_datasharing_writer_)
    {
        // Send initial NACK.
        SequenceNumberSet_t sns(SequenceNumber_t(0, 0));
      	// 同进程
        if (is_on_same_process_)
        {
            RTPSWriter* writer = RTPSDomainImpl::find_local_writer(guid());
            if (writer)
            {
                bool tmp;
                writer->process_acknack(guid(), reader_->getGuid(), 1, SequenceNumberSet_t(), false, tmp);
            }
        }
        else
        {
        // 不是一个进程的,如果没有收到过心跳,则主动发送acknack
        // last_heartbeat_count_表示之前收到心跳的最后一个id,初始化值为0
            if (0 == last_heartbeat_count_)
            {
                reader_->send_acknack(this, sns, this, false);
                double time_ms = initial_acknack_->getIntervalMilliSec();
                constexpr double max_ms = 60 * 60 * 1000; // Limit to 1 hour
                if (time_ms < max_ms)
                {
                    initial_acknack_->update_interval_millisec(time_ms * 2);
                    ret_value = true;
                }
            }
        }
    }

    expected = StateCode::BUSY;
    state_.compare_exchange_strong(expected, StateCode::IDLE);

    return ret_value;
}

上面的函数主要执行的是发送acknack的操作

分为2种情况

1.是同进程,直接执行接收消息的操作

2.跨设备发送acknack,调用StatefulReader的send_acknack函数

跨设备发送这个初始化的acknack是有条件的,就是需要之前没有收到过心跳。

如果对端相应节点收到这个init acknack包,则回应一个hearbeat,StatefulReader收到heartbeat会再发送一个acknack消息。

发送完毕之后会重新设置间隔时间,这儿设置成2个小时。

init acknack一般不会发送出来,只有在StatefulWriter 发送heartbeat没有传送过来的时候才会出现,这个概率其实不高。比较难出现。

void StatefulReader::send_acknack(
        const WriterProxy* writer,
        const SequenceNumberSet_t& sns,
        RTPSMessageSenderInterface* sender,
        bool is_final)
{

    std::unique_lock<RecursiveTimedMutex> lock(mp_mutex);

    if (!writer->is_alive())
    {
        return;
    }

    if (writer->is_on_same_process())
    {
        return;
    }

    acknack_count_++;


    EPROSIMA_LOG_INFO(RTPS_READER, "Sending ACKNACK: " << sns);

    RTPSMessageGroup group(getRTPSParticipant(), this, sender);
    group.add_acknack(sns, acknack_count_, is_final);
}

调用RTPSMessageGroup的add_acknack加入

bool RTPSMessageGroup::add_acknack(
        const SequenceNumberSet_t& SNSet,
        int32_t count,
        bool finalFlag)
{
    ------

    check_and_maybe_flush();


    if (!RTPSMessageCreator::addSubmessageAcknack(submessage_msg_, endpoint_->getGuid().entityId,
            sender_->remote_guids().front().entityId, SNSet, count, finalFlag))
    {
        EPROSIMA_LOG_ERROR(RTPS_READER, "Cannot add ACKNACK submsg to the CDRMessage. Buffer too small");
        return false;
    }



    // Notify the statistics module, note that only readers add acknacks
    assert(nullptr != dynamic_cast<RTPSReader*>(endpoint_));
    static_cast<fastdds::statistics::StatisticsReaderImpl*>(static_cast<RTPSReader*>(endpoint_))->on_acknack(count);

    return insert_submessage(false);
}

参考FastDDS 源码解析(十一)发送第一条PDP消息(中),相关处理,这个比较类似了

1.4抓包

init acknack 的包

image-20240122111500146.png

//这个抓的包就是init acknack 的包,readerSNState 的bitmapBase 和 numBits 为0

一般是StatefulReader 发送给 StatefulWriter 的包

1.5类图

classDiagram
 EDPSimple *-- StatefulReader
      EDPSimple *-- StatefulWriter
      StatefulReader *-- WriterProxy
      WriterProxy *-- heartbeat_response_
      WriterProxy *-- initial_acknack_
      class StatefulReader{
      		+ResourceLimitedVector<WriterProxy*> matched_writers
      }
      class WriterProxy{
      		+TimedEvent* heartbeat_response_
      		+TimedEvent* initial_acknack_
      }

我们看到

1.EDPSimple有StatefulReader 和 StatefulWriter

2.StatefulReader有一个队列存放了和这个StatefulReader对应的writer的信息,也就是这个writer的代理,WriterProxy

3.WriterProxy内有两个TimedEvent,heartbeat_response 和Initial_acknack

Initial_acknack 就是会发送初始化的acknack 消息,如果先收到对端的heartbeat,那么就不发送,如果没有收到heartbeat就发送这个初始化的acknack

heartbeat_response就是在收到对端的heartbeat后发送acknack消息。

车载消息中间件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消息(上)

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

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