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);
}