2.2、DomainParticipant::enable()分析
ReturnCode_t DomainParticipant::enable()
{
if (enable_)
{
return ReturnCode_t::RETCODE_OK;
}
enable_ = true;
//调用DomainParticipantImpl的enable()
ReturnCode_t ret_code = impl_->enable();
enable_ = !!ret_code;
return ret_code;
}
可见调用了DomainParticipantImpl::enable()
ReturnCode_t DomainParticipantImpl::enable()
{
fastrtps::rtps::RTPSParticipantAttributes rtps_attr;
//用qos填充attr,构建RTPSParticipant时用
utils::set_attributes_from_qos(rtps_attr, qos_);
rtps_attr.participantID = participant_id_;
//返回空
RTPSParticipant* part = RTPSDomainImpl::clientServerEnvironmentCreationOverride(
domain_id_,
false,
rtps_attr,
&rtps_listener_);
if (part == nullptr)
{
//创建RTPSParticipant
part = RTPSDomain::createParticipant(domain_id_, false, rtps_attr, &rtps_listener_);
}
//获取guid
guid_ = part->getGuid();
{
std::lock_guard<std::mutex> _(mtx_gs_);
rtps_participant_ = part;
}
//执行RTPSParticipant的enable()
part->enable();
return ReturnCode_t::RETCODE_OK;
}
主要是创建RTPSParticipant,并执行其enable()
createParticipant如下
//创建RTPSParticipant
RTPSParticipant* p = new RTPSParticipant(nullptr);
RTPSParticipantImpl* pimpl = nullptr;
if (PParam.prefix != c_GuidPrefix_Unknown)
{
}
else
{
//创建RTPSParticipantImpl
pimpl = new RTPSParticipantImpl(domain_id, PParam, guidP, p, listen);
}
if (enabled)
{
// Start protocols
pimpl->enable();
}
构造一个RTPSParticipantImpl
执行其enable()函数
2.2.1 RTPSParticipantImpl构造函数
if (c_GuidPrefix_Unknown != persistence_guid)
{
//设置guid
m_persistence_guid = GUID_t(persistence_guid, c_EntityId_RTPSParticipant);
}
// Builtin transports by default
if (PParam.useBuiltinTransports)//内置transport
{
UDPv4TransportDescriptor descriptor;// UDPv4transport
descriptor.sendBufferSize = m_att.sendSocketBufferSize;
descriptor.receiveBufferSize = m_att.listenSocketBufferSize;
if (is_intraprocess_only())
{
// Avoid multicast leaving the host for intraprocess-only participants
descriptor.TTL = 0;
}
//向mRegisteredTransports这个vector中填充内置的transport
m_network_Factory.RegisterTransport(&descriptor, &m_att.properties);
}
std::vector<std::unique_ptr<fastdds::rtps::TransportInterface>> mRegisteredTransports;
// 填充User defined transports
for (const auto& transportDescriptor : PParam.userTransports)
{
if (m_network_Factory.RegisterTransport(transportDescriptor.get(), &m_att.properties))
{
}
}
1.createReceiverResources
createReceiverResources(m_att.builtin.metatrafficMulticastLocatorList, true, false);
createReceiverResources(m_att.builtin.metatrafficUnicastLocatorList, true, false);
createReceiverResources(m_att.defaultUnicastLocatorList, true, false);
createReceiverResources(m_att.defaultMulticastLocatorList, true, false);
以上是创建receiver的接口,该接口会从mRegisteredTransports(内置或用户填充)中取出transport创建用于接收的UDPv4Transport,Multicast和Unicast类型。
其中 metatrafficMulticastLocatorList的成员数为1,metatrafficUnicastLocatorList成员数为2,defaultUnicastLocatorList成员数为2,defaultMulticastLocatorList成员数为0。
则createReceiverResources(m_att.defaultMulticastLocatorList, true, false)不会创建UDPv4Transport。
因此以上共会创建3个UDPv4Transport,用于接收udp单播、广播。追踪一下具体创建过程:
bool RTPSParticipantImpl::createReceiverResources(
LocatorList_t& Locator_list,
bool ApplyMutation,
bool RegisterReceiver)
{
std::vector<std::shared_ptr<ReceiverResource>> newItemsBuffer;
bool ret_val = Locator_list.empty();
uint32_t max_receiver_buffer_size = std::numeric_limits<uint32_t>::max();
//从Locator_list中逐个取出Locator作为参数创建ReceiverResources
for (auto it_loc = Locator_list.begin(); it_loc != Locator_list.end(); ++it_loc)
{
//创建后填入容器newItemsBuffer(临时容器)
bool ret = m_network_Factory.BuildReceiverResources(*it_loc, newItemsBuffer, max_receiver_buffer_size);
ret_val |= !newItemsBuffer.empty();
//从newItemsBuffer取出新创建的ReceiverResource放入m_receiverResourcelist
for (auto it_buffer = newItemsBuffer.begin(); it_buffer != newItemsBuffer.end(); ++it_buffer)
{
std::lock_guard<std::mutex> lock(m_receiverResourcelistMutex);
//Push the new items into the ReceiverResource buffer
m_receiverResourcelist.emplace_back(*it_buffer);
//Create and init the MessageReceiver
auto mr = new MessageReceiver(this, (*it_buffer)->max_message_size());
//设置该 ReceiverResource的 MessageReceiver
m_receiverResourcelist.back().mp_receiver = mr;
//Start reception
if (RegisterReceiver)
{
m_receiverResourcelist.back().Receiver->RegisterReceiver(mr);
}
}
newItemsBuffer.clear();
}
return ret_val;
}
该函数的主要逻辑如下:
1.从Locator_list中逐个取出Locator用于创建ReceiverResource
2.将ReceiverResource放入m_receiverResourcelist列表
BuildReceiverResources具体创建过程:
bool NetworkFactory::BuildReceiverResources(
Locator_t& local,
std::vector<std::shared_ptr<ReceiverResource>>& returned_resources_list,
uint32_t receiver_max_message_size)
{
bool returnedValue = false;
//从mRegisteredTransports容器中取出transport
for (auto& transport : mRegisteredTransports)
{
//判断locator.kind == transport_kind_?
if (transport->IsLocatorSupported(local))
{ //判断是否未open
if (!transport->IsInputChannelOpen(local))
{
uint32_t max_recv_buffer_size = (std::min)(
transport->max_recv_buffer_size(),
receiver_max_message_size);
//构建ReceiverResource
std::shared_ptr<ReceiverResource> newReceiverResource = std::shared_ptr<ReceiverResource>( new ReceiverResource(*transport, local, max_recv_buffer_size));
if (newReceiverResource->mValid)
{
//填入临时容器
returned_resources_list.push_back(newReceiverResource);
returnedValue = true;
}
}
else
{
returnedValue = true;
}
}
}
return returnedValue;
}
其中mRegisteredTransports是在NetworkFactory::RegisterTransport接口中被填充。
接下分析ReceiverResource构造函数:
transport.OpenInputChannel(locator, this, max_message_size_);
调用的是UDPv4Transport::OpenInputChannel,该方法主要逻辑如下:
调用OpenAndBindInputSockets创建socket,开启接收线程
success = OpenAndBindInputSockets(locator, receiver, IPLocator::isMulticast(locator), maxMsgSize);
UDPTransportInterface::OpenAndBindInputSockets分析:
//vOutputInterfaces.push_back(s_IPv4AddressAny),填入的是0.0.0.0
std::vector<std::string> vInterfaces = get_binding_interfaces_list();
for (std::string sInterface : vInterfaces)
{
UDPChannelResource* p_channel_resource;
//这里创建socket,传入的IP是 0.0.0.0
p_channel_resource = CreateInputChannelResource(sInterface, locator, is_multicast, maxMsgSize, receiver);
//port:UDPChannelResource 组成 key:value
mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(p_channel_resource);
}
CreateInputChannelResource会创建socket返回 UDPChannelResource
UDPChannelResource与对应的port存入map容器mInputSockets
UDPChannelResource* UDPTransportInterface::CreateInputChannelResource(
const std::string& sInterface,
const Locator& locator,
bool is_multicast,
uint32_t maxMsgSize,
TransportReceiverInterface* receiver)
{
//创建socket,入参为IP Port
eProsimaUDPSocket unicastSocket = OpenAndBindInputSocket(sInterface,
IPLocator::getPhysicalPort(locator), is_multicast);
//用socket创建UDPChannelResource
UDPChannelResource* p_channel_resource = new UDPChannelResource(this, unicastSocket, maxMsgSize, locator,sInterface, receiver);
//返回创建好的UDPChannelResource指针
return p_channel_resource;
}
1.创建socket过程:
eProsimaUDPSocket UDPv4Transport::OpenAndBindInputSocket(
const std::string& sIp,
uint16_t port,
bool is_multicast)
{
//创建socket
eProsimaUDPSocket socket = createUDPSocket(io_service_);
getSocketPtr(socket)->open(generate_protocol());
if (mReceiveBufferSize != 0)
{
//设置接收buffer大小
getSocketPtr(socket)->set_option(socket_base::receive_buffer_size(mReceiveBufferSize));
}
if (is_multicast)
{
//设置REUSEADDR,允许socket绑定已使用的地址
getSocketPtr(socket)->set_option(ip::udp::socket::reuse_address(true));
}
//绑定端口号 74xx , IP地址 0.0.0.0
getSocketPtr(socket)->bind(generate_endpoint(sIp, port));
return socket;
}
这里注意一点0.0.0.0
IPV4中,0.0.0.0地址被用于表示一个无效的,未知的或者不可用的目标。
在服务器中,0.0.0.0指的是本机上的所有IPV4地址,如果一个主机有两个IP地址,127.0.0.1和 10.0.2.15,并且该主机上的一个服务监听的地址是0.0.0.0,那么通过访问这两个ip地址都能够访问该服务。
这里补充一点,后面将本机IP加入到239.255.0.1组播中,则该socket绑定0.0.0.0可以收到发往本机的组播帧。
在路由中,0.0.0.0表示的是默认路由,即当路由表中没有找到完全匹配的路由的时候所对应的路由。