车载消息中间件FastDDS 源码解析(四)RtpsParticipant的创建(下)

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

6.createReceiverResources

根据之前获取的metatrafficMulticastLocatorList,metatrafficUnicastLocatorList,defaultUnicastLocatorList,defaultMulticastLocatorList来创建 ReceiverResources

arduino 复制代码
 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);

6.1createReceiverResources的时序图

sequenceDiagram participant RTPSParticipantImpl participant NetworkFactory participant ReceiverResource participant UDPv4Transport participant UDPTransportInterface Participant FlowControllerFactory participant BuiltinProtocols RTPSParticipantImpl ->> RTPSParticipantImpl: 1.createReceiverResources RTPSParticipantImpl ->> NetworkFactory: 2.BuildReceiverResources NetworkFactory ->> ReceiverResource: 3.new ReceiverResource ReceiverResource ->> UDPv4Transport: 4.OpenInputChannel UDPv4Transport ->>UDPTransportInterface: 5.OpenAndBindInputSockets UDPTransportInterface ->> UDPTransportInterface: 6.CreateInputChannelResource UDPTransportInterface ->> UDPv4Transport: 7.OpenAndBindInputSocket RTPSParticipantImpl ->> FlowControllerFactory: 8.init RTPSParticipantImpl->>BuiltinProtocols: 9.new
  1. createReceiverResources主要干了2件事,创建receiverresource 和 对应的messagereceiver

    为每个Locator 创建ReceiverResource,如果receiverresource创建失败(主要原因可能是端口号被占用),更改端口号,继续创建,试100次,为每个receiverResource 创建一个messagereceiver,receiverresource和messagereceiver,存放到RTPSParticipantImpl的 m_receiverResourcelist里面去。更改端口号可能导致pdp阶段无法建连

  2. BuildReceiverResources 这个函数里面主要,根据已经注册的Transports :mRegisteredTransports, new ReceiverResource

  3. new ReceiverResource 这个初始化函数,主要是调用了Transport的 OpenInputChannel函数,我们以UDPv4Transport 为例继续往下看

  4. UDPv4Transport 的OpenInputChannel 函数 主要是干了2件事

    a.OpenAndBindInputSockets 主要是创建了对应的socket 和 channelresource,这个socket 和 channelresource 是一一对应的,

    主要根据 locator 的port 和 interface_whitelist_ 中的ip 创建channelResource

    b.针对多播的情况一般需要新建一个 channelResource

  5. UDPTransportInterface 的函数OpenAndBindInputSockets 主要调用CreateInputChannelResource,创建channelresource

    将channelresource 存入mInputSockets,mInputSockets以port 为key,以vector为value

  6. UDPTransportInterface的函数CreateInputChannelResource 主要干了2件事:

    a.OpenAndBindInputSocket 主要是创建了一个socket

    b.在OpenAndBindInputSocket 创建的socket的基础上new 了一个UDPChannelResource,每个UDPChannelResource 配置一个thread,循环接收消息

  7. OpenAndBindInputSocket 创建socket, 配置socket

  8. FlowControllerFactory 的init函数 这个在第三篇中详细介绍

  9. new 了 BuiltinProtocols 这个在第四篇中详细介绍

6.2createReceiverResources的源码

先看步骤1:

scss 复制代码
 bool RTPSParticipantImpl::createReceiverResources(
         LocatorList_t& Locator_list,
         bool ApplyMutation,
         bool RegisterReceiver)
 {
     std::vector<std::shared_ptr<ReceiverResource>> newItemsBuffer;
     bool ret_val = Locator_list.empty();
 ​
 ······
 ​
     // 为每个Locator 创建ReceiverResource
     for (auto it_loc = Locator_list.begin(); it_loc != Locator_list.end(); ++it_loc)
    {
         // 如果receiverresource创建失败(主要原因可能是端口号被占用),更改端口号,继续创建,
         // 尝试次数m_att.builtin.mutation_tries
         bool ret = m_network_Factory.BuildReceiverResources(*it_loc, newItemsBuffer, max_receiver_buffer_size);
         if (!ret && ApplyMutation)
        {
             uint32_t tries = 0;
             while (!ret && (tries < m_att.builtin.mutation_tries))
            {
                 tries++;
                 applyLocatorAdaptRule(*it_loc);
                 ret = m_network_Factory.BuildReceiverResources(*it_loc, newItemsBuffer, max_receiver_buffer_size);
            }
        }
 ​
         ret_val |= !newItemsBuffer.empty();
         // 为每个receiverResource 创建一个messagereceiver
         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());
             //
             m_receiverResourcelist.back().mp_receiver = mr;
             //Start reception
             // 将receiverresource 与 MessageReceiver 关联,关联后可以接收message了
             if (RegisterReceiver)
            {
                 m_receiverResourcelist.back().Receiver->RegisterReceiver(mr);
            }
        }
         newItemsBuffer.clear();
    }
 ​
     return ret_val;
 }
 ​
    

bool RTPSParticipantImpl::createReceiverResources()

这个函数,主要干了2件事

1.根据LocatorList_t& Locator_list ,通过传入的Locator来创建ReceiverResource,这个ReceiverResource主要是一个socket 和这个socket对应的参数,

2.创建MessageReceiver来处理,socket收到的消息都是交给MessageReceiver处理的。

先看如何创建ReceiverResource,NetworkFactory::BuildReceiverResources来创建ReceiverResource

步骤2:BuildReceiverResources

c 复制代码
 bool NetworkFactory::BuildReceiverResources(
         Locator_t& local,
         std::vector<std::shared_ptr<ReceiverResource>>& returned_resources_list,
         uint32_t receiver_max_message_size)
 {
     bool returnedValue = false;
     for (auto& transport : mRegisteredTransports)
    {
         if (transport->IsLocatorSupported(local))
        {
           // 有没有相应的socket
             if (!transport->IsInputChannelOpen(local))
            {
                 uint32_t max_recv_buffer_size = (std::min)(
                     transport->max_recv_buffer_size(),
                     receiver_max_message_size);
 ​
                 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;
 }

NetworkFactory::BuildReceiverResources 的主要参数是Locator_t& local

通过NetworkFactory中注册的transport来创建ReceiverResource,主要new了ReceiverResource

步骤3 new ReceiverResource

scss 复制代码
 ReceiverResource::ReceiverResource(
         TransportInterface& transport,
         const Locator_t& locator,
         uint32_t max_recv_buffer_size)
    : Cleanup(nullptr)
    , LocatorMapsToManagedChannel(nullptr)
    , mValid(false)
    , mtx()
    , cv_()
    , receiver(nullptr)
    , max_message_size_(max_recv_buffer_size)
    , active_callbacks_(0)
 {
     // Internal channel is opened and assigned to this resource.
     mValid = transport.OpenInputChannel(locator, this, max_message_size_);
     if (!mValid)
    {
         return; // Invalid resource to be discarded by the factory.
    }
 ​
     // Implementation functions are bound to the right transport parameters
     Cleanup = [&transport, locator]()
            {
                 transport.CloseInputChannel(locator);
            };
     LocatorMapsToManagedChannel = [&transport, locator](const Locator_t& locatorToCheck) -> bool
            {
                 return locator.kind == locatorToCheck.kind && transport.DoInputLocatorsMatch(locator, locatorToCheck);
            };
 }

ReceiverResource::ReceiverResource的主要参数是TransportInterface& transport,const Locator_t& locator,主要调用了transport.OpenInputChannel来创建,

我们这边以UDPv4Transport来举例

步骤4 UDPv4Transport 的OpenInputChannel

rust 复制代码
 bool UDPv4Transport::OpenInputChannel(
         const Locator& locator,
         TransportReceiverInterface* receiver,
         uint32_t maxMsgSize)
 {
     std::unique_lock<std::recursive_mutex> scopedLock(mInputMapMutex);
     if (!is_locator_allowed(locator))
    {
         return false;
    }
 ​
     bool success = false;
 
   // 保证这个locator有一个对应的socket
     if (!IsInputChannelOpen(locator))
    {
         // 根据 locator 的port 和 interface_whitelist_ 中的ip 创建channelResource
         success = OpenAndBindInputSockets(locator, receiver, IPLocator::isMulticast(locator), maxMsgSize);
    }
 ​
     // 针对多播的情况一般需要 需要新建一个 channelResource
     // IsInputChannelOpen 主要是看port 有没有对应的 channelResource
     if (IPLocator::isMulticast(locator) && IsInputChannelOpen(locator))
    {
         //ip地址
         std::string locatorAddressStr = IPLocator::toIPv4string(locator);
         ip::address_v4 locatorAddress = ip::address_v4::from_string(locatorAddressStr);
 ​
 #ifndef _WIN32
         // 非windows的系统里面 如果interface_whitelist_ 不为空
         if (!is_interface_whitelist_empty())
        {
             // Either wildcard address or the multicast address needs to be bound on non-windows systems
             bool found = false;
 ​
             // First check if the multicast address is already bound
             auto& channelResources = mInputSockets.at(IPLocator::getPhysicalPort(locator));
             for (UDPChannelResource* channelResource : channelResources)
            {
                 if (channelResource->interface() == locatorAddressStr)
                {
                     // 能找到相应的channelResource
                     found = true;
                     break;
                }
            }
 ​
             // Create a new resource if no one is found
             if (!found)
            {
                 try
                {
                     // Bind to multicast address
                     // 如果没有找到UDPChannelResource,创建一个
                     UDPChannelResource* p_channel_resource;
                     // locatorAddressStr, locator 一一对应的关系
                     p_channel_resource = CreateInputChannelResource(locatorAddressStr, locator, true, maxMsgSize, receiver);
                     mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(p_channel_resource);
 ​
                     // Join group on all whitelisted interfaces
                     // 配置多播参数
                     for (auto& ip : interface_whitelist_)
                    {
                         // locatorAddress多播地址,ip是本机地址
                         // socket 加入多播组
                         p_channel_resource->socket()->set_option(ip::multicast::join_group(locatorAddress, ip));
                    }
                }
               ------   
            }
        }
         else
 #endif // ifndef _WIN32
         ------
 ​
     return success;
 }

UDPv4Transport::OpenInputChannel 主要

1.调用的OpenAndBindInputSockets,根据本地ip地址 创建socket

2.如果是多播,加入多播组,配置相应参数,这里面会根据平台区分,win32的有win32的加入方式,其他平台有其他平台的加入方式。

步骤5 OpenAndBindInputSockets

c 复制代码
 bool UDPTransportInterface::OpenAndBindInputSockets(
         const Locator& locator,
         TransportReceiverInterface* receiver,
         bool is_multicast,
         uint32_t maxMsgSize)
 {
     
 ······
     try
    {   
       //interface_whitelist_ 为空,把地址0 放入interface_whitelist_ 
         std::vector<std::string> vInterfaces = get_binding_interfaces_list();
         //本机的ip地址,根据本机的ip地址,创建ChannelResource,ChannelResource的interface 是ip地址
         for (std::string sInterface : vInterfaces)
        {
             UDPChannelResource* p_channel_resource;
             // 主要用到的是 locator 的port 和 interface_whitelist_的ip
             p_channel_resource = CreateInputChannelResource(sInterface, locator, is_multicast, maxMsgSize, receiver);
             mInputSockets[IPLocator::getPhysicalPort(locator)].push_back(p_channel_resource);
        }
    }
     
 ······
     return true;
 }

主要干了2件事

1.get_binding_interfaces_list 获取本地ip地址,

2.使用获取的ip地址CreateInputChannelResource创建channelresource ,channelresource主要是socket,和socket 对应的参数,每个channelresource 有个线程,不断接收消息,收到消息之后交给messagereceiver处理。

c 复制代码
 std::vector<std::string> UDPv4Transport::get_binding_interfaces_list()
 {
     std::vector<std::string> vOutputInterfaces;
   // 如果白名单为空,则将0.0.0.0放入
     if (is_interface_whitelist_empty())
    {
         vOutputInterfaces.push_back(s_IPv4AddressAny);
    }
     else
    {
         for (auto& ip : interface_whitelist_)
        {
             vOutputInterfaces.push_back(ip.to_string());
        }
    }
 ​
     return vOutputInterfaces;
 }

udpv4transport 的属性 interface_whitelist_ 最少包含一个ip地址

如果为空,会用0.0.0.0填充进去

步骤6:根据locator 调用CreateInputChannelResource

arduino 复制代码
 UDPChannelResource* UDPTransportInterface::CreateInputChannelResource(
         const std::string& sInterface,
         const Locator& locator,
         bool is_multicast,
         uint32_t maxMsgSize,
         TransportReceiverInterface* receiver)
 {
     // 生成一个socket
     eProsimaUDPSocket unicastSocket = OpenAndBindInputSocket(sInterface,
                     IPLocator::getPhysicalPort(locator), is_multicast);
     // 每个channelresource 有个线程,不断接收消息
     UDPChannelResource* p_channel_resource = new UDPChannelResource(this, unicastSocket, maxMsgSize, locator,
                     sInterface, receiver);
     return p_channel_resource;
 }
 ​

1.调用UDPv4Transport::OpenAndBindInputSocket创建一个socket

2.创建UDPChannelResource的时候,会创建一个线程不断循环,接收socket数据

步骤7:

scss 复制代码
 eProsimaUDPSocket UDPv4Transport::OpenAndBindInputSocket(
         const std::string& sIp,
         uint16_t port,
         bool is_multicast)
 {
     eProsimaUDPSocket socket = createUDPSocket(io_service_);
     getSocketPtr(socket)->open(generate_protocol());
     if (mReceiveBufferSize != 0)
    {
         getSocketPtr(socket)->set_option(socket_base::receive_buffer_size(mReceiveBufferSize));
    }
 ​
     if (is_multicast)
    {
         getSocketPtr(socket)->set_option(ip::udp::socket::reuse_address(true));
 #if defined(__QNX__)
         getSocketPtr(socket)->set_option(asio::detail::socket_option::boolean<
                     ASIO_OS_DEF(SOL_SOCKET), SO_REUSEPORT>(true));
 #endif // if defined(__QNX__)
    }
 ​
     getSocketPtr(socket)->bind(generate_endpoint(sIp, port));
     return socket;
 }

创建socket,配置参数

上面这些代码主要是为了创建接收的socket,如果有白名单,则根据白名单和本地ip地址的交集来创建socket,如果白名单为空,则根据ip地址0.0.0.0来创建接收的socket。

多播 和 单播的端口号是不一样的。builtin 的单播的端口号,和非builtin的单播的端口号也是不一样的

css 复制代码
 UDPChannelResource::UDPChannelResource(
        )
 {
     thread(std::thread(&UDPChannelResource::perform_listen_operation, this, locator));
 }

在这儿就是创建了一个线程,不断接收数据

6.2类图

classDiagram RTPSParticipantImpl *-- ReceiverControlBlock ReceiverControlBlock *-- ReceiverResource ReceiverControlBlock *-- MessageReceiver ReceiverResource *-- MessageReceiver UDPTransportInterface <|-- UDPV4Transport UDPV4Transport *-- UDPChannelResource UDPChannelResource *-- ReceiverResource class RTPSParticipantImpl { +std::list m_receiverResourcelist } class ReceiverControlBlock { +std::shared_ptr Receiver +MessageReceiver* mp_receiver } class ReceiverResource { +MessageReceiver* receiver } class MessageReceiver{ } class UDPV4Transport{ +std::map> mInputSockets } class UDPChannelResource{ +TransportReceiverInterface* message_receiver_ +eProsimaUDPSocket socket_ }

createReceiverResources(m_att.builtin.metatrafficMulticastLocatorList, true, false);

builtin 是每个participant 自带的,builtin.metatrafficMulticastLocatorList的ip地址默认是239.255.0.1

这里面应该是创建了多个socket监听,如果有白名单ip,地址就对白名单ip地址和本地ip地址(包括回环地址127.0.0.1)的交集监听,如果没有就对0.0.0.0的ip地址做监听,这些ip地址,加入到 239.255.0.1的多播地址group

createReceiverResources(m_att.builtin.metatrafficUnicastLocatorList, true, false);

builtin.metatrafficUnicastLocatorList 的ip地址默认是0

这里面应该是创建了多个socket监听,如果有白名单ip,地址就对白名单ip地址和本地ip地址(包括回环地址127.0.0.1)的交集监听,如果没有就对0.0.0.0的ip地址做监听

createReceiverResources(m_att.defaultUnicastLocatorList, true, false); createReceiverResources(m_att.defaultMulticastLocatorList, true, false);

7.flow_controller

在RTPSParticipantImpl的构造函数当中,初始化了flow_controller_factory_,同时根据配置参数,register_flow_controller,

下面是RTPSParticipantImpl 构造函数中的相关代码

ini 复制代码
 //初始化flow_controller_factory_
 flow_controller_factory_.init(this);
 ​
     // Support old API
     if (PParam.throughputController.bytesPerPeriod != UINT32_MAX && PParam.throughputController.periodMillisecs != 0)
    {
         fastdds::rtps::FlowControllerDescriptor old_descriptor;
         old_descriptor.name = guid_str_.c_str();
         old_descriptor.max_bytes_per_period = PParam.throughputController.bytesPerPeriod;
         old_descriptor.period_ms = PParam.throughputController.periodMillisecs;
         flow_controller_factory_.register_flow_controller(old_descriptor);
    }
 ​
     // Register user's flow controllers.
 //注册自定义的flow_controller
     for (auto flow_controller_desc : m_att.flow_controllers)
    {
         flow_controller_factory_.register_flow_controller(*flow_controller_desc.get());
    }

主要干了2件事

1.初始化flow_controller_factory_,在这里初始化了3-4个默认的flow_controller

2.注册自定义的flow_controller

arduino 复制代码
 void FlowControllerFactory::init(
         fastrtps::rtps::RTPSParticipantImpl* participant)
 {
     participant_ = participant;
     // Create default flow controllers.
 ​
     // PureSyncFlowController -> used by 
   besteffort writers.
     flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                 pure_sync_flow_controller_name,
                 std::unique_ptr<FlowController>(
                     new FlowControllerImpl<FlowControllerPureSyncPublishMode,
                     FlowControllerFifoSchedule>(participant_, nullptr))));
     // SyncFlowController -> used by rest of besteffort writers.
     flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                 sync_flow_controller_name,
                 std::unique_ptr<FlowController>(
                     new FlowControllerImpl<FlowControllerSyncPublishMode,
                     FlowControllerFifoSchedule>(participant_, nullptr))));
     // AsyncFlowController
     flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                 async_flow_controller_name,
                 std::unique_ptr<FlowController>(
                     new FlowControllerImpl<FlowControllerAsyncPublishMode,
                     FlowControllerFifoSchedule>(participant_, nullptr))));
 ​
 #ifdef FASTDDS_STATISTICS
     flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                 async_statistics_flow_controller_name,
                 std::unique_ptr<FlowController>(
                     new FlowControllerImpl<FlowControllerAsyncPublishMode,
                     FlowControllerFifoSchedule>(participant_, nullptr))));
 #endif // ifndef FASTDDS_STATISTICS
 }
 ​

//在初始化函数中初始化了3个默认的flow_controller,这3个 flow_controller,

FlowControllerImpl<FlowControllerPureSyncPublishMode,FlowControllerFifoSchedule>

FlowControllerImpl<FlowControllerSyncPublishMode,FlowControllerFifoSchedule>

FlowControllerImpl<FlowControllerAsyncPublishMode,FlowControllerFifoSchedule>

如果有STATISTICS的话,会初始化一个适用于STATISTICS的flow_controller

这3个看字面意思是这样的,

第一个纯同步的,先进先出(fifo)的发送模式,纯同步就是完全没有异步发送方式

第二个同步的,先进先出(fifo)的发送模式,如果同步发送不成功,则异步发送

第三个异步的,先进先出(fifo)的发送模式,异步的就是没有同步发送的方式,都是异步发送

FlowControllerFifoSchedule表示的是发送模式,什么意思哪,就是我们有个发送消息的队列,所有的发送消息进队列,然后发送顺序是先进先出

php 复制代码
 void FlowControllerFactory::register_flow_controller (
         const FlowControllerDescriptor& flow_controller_descr)
 {
     if (flow_controllers_.end() != flow_controllers_.find(flow_controller_descr.name))
    {
         EPROSIMA_LOG_ERROR(RTPS_PARTICIPANT,
                 "Error registering FlowController " << flow_controller_descr.name << ". Already registered");
         return;
    }
     //如果设置流量控制
     if (0 < flow_controller_descr.max_bytes_per_period)
    {
         switch (flow_controller_descr.scheduler)
        {
             case FlowControllerSchedulerPolicy::FIFO:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerLimitedAsyncPublishMode,
                                 FlowControllerFifoSchedule>(participant_, &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::ROUND_ROBIN:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerLimitedAsyncPublishMode,
                                 FlowControllerRoundRobinSchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::HIGH_PRIORITY:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerLimitedAsyncPublishMode,
                                 FlowControllerHighPrioritySchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::PRIORITY_WITH_RESERVATION:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerLimitedAsyncPublishMode,
                                 FlowControllerPriorityWithReservationSchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             default:
                 assert(false);
        }
    }
     else
    {
         switch (flow_controller_descr.scheduler)
        {
             case FlowControllerSchedulerPolicy::FIFO:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerAsyncPublishMode,
                                 FlowControllerFifoSchedule>(participant_, &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::ROUND_ROBIN:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerAsyncPublishMode,
                                 FlowControllerRoundRobinSchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::HIGH_PRIORITY:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerAsyncPublishMode,
                                 FlowControllerHighPrioritySchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             case FlowControllerSchedulerPolicy::PRIORITY_WITH_RESERVATION:
                 flow_controllers_.insert(decltype(flow_controllers_)::value_type(
                             flow_controller_descr.name,
                             std::unique_ptr<FlowController>(
                                 new FlowControllerImpl<FlowControllerAsyncPublishMode,
                                 FlowControllerPriorityWithReservationSchedule>(participant_,
                                 &flow_controller_descr))));
                 break;
             default:
                 assert(false);
        }
    }
 }

//这个函数是注册自定义的flow_controller,这个需要为flow_controller配置一些参数,然后FlowControllerFactory根据配置的参数生成不同类型的FlowController

flow_controller_descr.max_bytes_per_period 这个参数是对传输限速,

FlowControllerSchedulerPolicy有四种类型,如下所示:

FlowControllerSchedulerPolicy::FIFO

FlowControllerSchedulerPolicy::ROUND_ROBIN

FlowControllerSchedulerPolicy::HIGH_PRIORITY

FlowControllerSchedulerPolicy::PRIORITY_WITH_RESERVATION

除了在上面介绍的fifo之外,还有ROUND_ROBIN ,HIGH_PRIORITY,PRIORITY_WITH_RESERVATION

ROBIN是轮询,

HIGH_PRIORITY按照优先级发送,

PRIORITY_WITH_RESERVATION是按照优先级,同时兼顾公平,每个writer有个最少的带宽

每一个writer都有一个配套的flow_controller,flow_controller控制了writer 发送消息的策略和行为。

总结一下,关于RtpsParticipant的创建,我们围绕RtpsParticipant的构造函数,写了3篇,RtpsParticipant的构造函数的6个部分,介绍了5个,还有1个BuiltinProtocols还没有介绍,这个部分内容很多将会分2篇介绍。

车载消息中间件FastDDS 源码解析(一)FastDDS 介绍和使用

车载消息中间件FastDDS 源码解析(二)RtpsParticipant的创建(上)

车载消息中间件FastDDS 源码解析(三)RtpsParticipant的创建(中)

相关推荐
HinGwenWoong9 小时前
Robot | 用 RDK 做一个小型机器人(更新中)
机器人
电报号dapp11911 小时前
链游系统定制化开发:引领游戏产业的新时代
游戏·机器人·去中心化·区块链
xiaoyaolangwj15 小时前
高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十三)图优化SLAM的本质
学习·机器人·自动驾驶
知行电子-1 天前
Proteus中数码管动态扫描显示不全(已解决)
单片机·proteus·嵌入式
花生树什么树2 天前
机器人操作臂逆运动学
机器人·逆运动学
anzocapital2 天前
anzocapital 昂首资本:外汇机器人趋势判断秘籍
机器人
旗晟机器人2 天前
化工防爆巡检机器人:在挑战中成长,为化工安全保驾护航
人工智能·机器人
QYR市场调研2 天前
手术机器人:精准医疗的新选择
机器人
小帅吖2 天前
Webots控制器编程
机器人·机器人仿真·webots
天行健王春城老师3 天前
基于TRIZ的教育机器人功能创新
经验分享·机器人