车载消息中间件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的创建(中)

相关推荐
中关村科金5 小时前
中关村科金智能客服机器人如何解决客户个性化需求与标准化服务之间的矛盾?
人工智能·机器人·在线客服·智能客服机器人·中关村科金
lshzdq1 天前
【机器人】机械臂轨迹和转矩控制对比
人工智能·算法·机器人
委员1 天前
基于NodeMCU的物联网电灯控制系统设计
单片机·物联网·嵌入式·nodemcu··lu_asr01·gy-302
夜幕龙1 天前
iDP3复现代码数据预处理全流程(二)——vis_dataset.py
人工智能·python·机器人
望获linux1 天前
赋能新一代工业机器人-望获实时linux在工业机器人领域应用案例
linux·运维·服务器·机器人·操作系统·嵌入式操作系统·工业控制
ai_lian_shuo2 天前
四、使用langchain搭建RAG:金融问答机器人--构建web应用,问答链,带记忆功能
python·ai·金融·langchain·机器人
我爱C编程2 天前
基于Qlearning强化学习的机器人路线规划matlab仿真
matlab·机器人·强化学习·路线规划·qlearning·机器人路线规划
野蛮的大西瓜2 天前
开源呼叫中心中,如何将ASR与IVR菜单结合,实现动态的IVR交互
人工智能·机器人·自动化·音视频·信息与通信
憧憬一下2 天前
PCIe_Host驱动分析_设备枚举
arm开发·嵌入式硬件·嵌入式·pcie·linux驱动开发
向阳逐梦3 天前
基于STM32F4单片机实现ROS机器人主板
stm32·单片机·机器人