RTPS通信使用的socket和端口
RTPS通信使用的socket和端口
概述
在FastRTPS中,无论SenderResource还是,ReceiverResource,其内部会依赖NetworkFactory创建socket,每个socket都需要绑定socket才能正常使用。
一般来说,一个RTPSParticipant中创建的RTPSReader/RTPSWriter都是共用一组socket资源的,而这些socket的端口的值一般是RTPSParticipant的domainid和participantid相关的。
上层应用可以指定创建的RTPSParticipant用于元数据和业务数据通信的单播地址/组播地址,但是无法指定通信的端口,端口是RTPS中根据规则进行计算分配的。
下面主要是梳理一下一个RTPSParticipant会创建哪些socket,每一类socket绑定的端口规则是怎样的。
创建的socket
通过阅读RTPSReader,RTPSWriter,StatelessWriter,StatelessReader,StatefulWriter以及StatefulReader的代码可以发现,这些endpoint类是只负责处理数据,管理匹配的对端endpoint,而发送和接收数据都是依赖内部的history对象的。history中的数据则是依赖了下层的ReceiverResource和SenderResource,而ReceiverResource和SenderResource是依赖了更下层Transport中的各种ChannelResource来进行网络数据通信的,每个ChannelResource中包含了用于地层数据通信的socket对象
发送
发送的Socket在SenderResource中创建,有如下几个创建的时机点
1. 创建RTPSParticipant设置qos的时候
DomainParticipantImpl::set_qos
RTPSParticipant::update_attributes
RTPSParticipantImpl::update_attributes
createSenderResources(元数据组播地址)
createSenderResources(元数据单播地址)
createSenderResources(业务数据单播地址)
NetworkFactory::build_send_resources
UDPTransportInterface::OpenOutputChannel
UDPTransportInterface::OpenAndBindUnicastOutputSocket
UDPTransportInterface::createUDPSocket
2. StatelessWriter匹配到对端Reader
StatelessWriter::matched_reader_add
StatelessWriter::update_reader_info
RTPSParticipantImpl::createSenderResources
3. StatefulWriter匹配到对端Reader
StatefulWriter::matched_reader_add
StatefulWriter::update_reader_info
RTPSParticipantImpl::createSenderResources
4. StatefulReader匹配到对端Writer(需要创建SenderResource用于发送ACKNACK消息)
StatefulReader::matched_writer_add
RTPSParticipantImpl::createSenderResources
接收
接收的Socket在ReceiverResource中创建,
元数据组播地址绑定的端口
https://gitee.com/zzl0109/Fast-DDS/blob/master/include/fastdds/rtps/common/PortParameters.h
inline uint32_t getMulticastPort(
uint32_t domainId) const
{
uint32_t port = portBase + domainIDGain * domainId + offsetd0;
...
return port;
}
元数据单播地址绑定的端口
https://gitee.com/zzl0109/Fast-DDS/blob/master/include/fastdds/rtps/common/PortParameters.h
inline uint32_t getUnicastPort(
uint32_t domainId,
uint32_t RTPSParticipantID) const
{
uint32_t port = portBase + domainIDGain * domainId + offsetd1 + participantIDGain * RTPSParticipantID;
...
return port;
}
业务数据单播地址绑定端口
https://gitee.com/zzl0109/Fast-DDS/blob/master/src/cpp/rtps/participant/RTPSParticipantImpl.cpp
...
RTPSParticipantImpl::RTPSParticipantImpl(
...
// 上层应用未指定单播和组播地址
if (m_att.defaultUnicastLocatorList.empty() && m_att.defaultMulticastLocatorList.empty())
{
get_default_unicast_locators();
internal_default_locators_ = true;
EPROSIMA_LOG_INFO(RTPS_PARTICIPANT,
m_att.getName() << " Created with NO default Unicast Locator List, adding Locators:"
<< m_att.defaultUnicastLocatorList);
}
else
{
// Locator with port 0, calculate port. 指定了地址,通过计算分配端口
std::for_each(m_att.defaultUnicastLocatorList.begin(), m_att.defaultUnicastLocatorList.end(),
[&](Locator_t& loc)
{ // 端口通过calculate_well_known_port计算
m_network_Factory.fill_default_locator_port(domain_id_, loc, m_att, false);
});
m_network_Factory.NormalizeLocators(m_att.defaultUnicastLocatorList);
std::for_each(m_att.defaultMulticastLocatorList.begin(), m_att.defaultMulticastLocatorList.end(),
[&](Locator_t& loc)
{ // 端口通过calculate_well_known_port计算
m_network_Factory.fill_default_locator_port(domain_id_, loc, m_att, true);
});
}
...
}
...
void RTPSParticipantImpl::get_default_unicast_locators()
{
m_network_Factory.getDefaultUnicastLocators(domain_id_, m_att.defaultUnicastLocatorList, m_att);
m_network_Factory.NormalizeLocators(m_att.defaultUnicastLocatorList);
}
...
https://gitee.com/zzl0109/Fast-DDS/blob/master/src/cpp/rtps/network/NetworkFactory.cpp
bool NetworkFactory::getDefaultUnicastLocators(
uint32_t domain_id,
LocatorList_t& locators,
const RTPSParticipantAttributes& m_att) const
{
bool result = false;
for (auto& transport : mRegisteredTransports)
{
result |= transport->getDefaultUnicastLocators(locators, calculate_well_known_port(domain_id, m_att, false));
}
return result;
}
bool NetworkFactory::fill_default_locator_port(
uint32_t domain_id,
Locator_t& locator,
const RTPSParticipantAttributes& m_att,
bool is_multicast) const
{
bool result = false;
for (auto& transport : mRegisteredTransports)
{
if (transport->IsLocatorSupported(locator))
{ // 端口通过calculate_well_known_port计算
result |= transport->fillUnicastLocator(locator, calculate_well_known_port(domain_id, m_att, is_multicast));
}
}
return result;
}
uint16_t NetworkFactory::calculate_well_known_port(
uint32_t domain_id,
const RTPSParticipantAttributes& att,
bool is_multicast) const
{
uint32_t port = att.port.portBase +
att.port.domainIDGain * domain_id +
(is_multicast ?
att.port.offsetd2 :
att.port.offsetd3 + att.port.participantIDGain * att.participantID);
if (port > 65535)
{
... // error log
exit(EXIT_FAILURE);
}
return static_cast<uint16_t>(port);
}
业务数据组播地址绑定端口