FastDDS源码解析三

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表示的是默认路由,即当路由表中没有找到完全匹配的路由的时候所对应的路由。

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值