车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用
车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)
车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)
车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)
车载消息中间件FastDDS 源码解析(五)BuiltinProtocols(上)
车载消息中间件FastDDS 源码解析(六)BuiltinProtocols(中)EDP
车载消息中间件FastDDS 源码解析(七)BuiltinProtocols(下)WLP&TypeLookupManager
车载消息中间件FastDDS 源码解析(八)TimedEvent
车载消息中间件FastDDS 源码解析(十)发送第一条PDP消息(上)
FastDDS 源码解析(十二)发送第一条PDP消息(下)---异步发送
FastDDS 源码解析(十三)发送第一条PDP消息---跨进程发送
FastDDS 源码解析(十六)处理PDP消息——PDP匹配
1.1EDP匹配
之前几篇我们介绍了接收到PDP消息之后的pdp匹配,由于多播的存在,在pdp匹配之前,就能接收到pdp多播的消息,只是在pdp匹配之后,我们也可以发送和接收单播的消息。
下面几篇我们介绍一下EDP的匹配,在EDP匹配之前一般是不能发送和接收EDP消息的。
我们可以看到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 的包
//这个抓的包就是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 源码解析(十)发送第一条PDP消息(上)
FastDDS 源码解析(十二)发送第一条PDP消息(下)---异步发送