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

上一篇主要介绍的FastDds的基本使用,同时介绍了使用过程中需要创建的对象,我们将针对这些对象逐一介绍,现在先开始介绍DomainParticipant的创建,内容比较多分3篇介绍。

1.DomainParticipant

上一篇中我们可以看到无论是发送端还是接收端,首先需要创建的就是dds两层结构的上面这一层(DCPS)的DomainParticipant

DomainParticipantFactory 调用create_participant主要干了三件事情:

a.new DomainParticipant()

b.new DomainParticipantImpl() 在这里DomainParticipant 和DomainParticipantImpl对象是一一对应关系

c.调用DomainParticipant对象的enable函数 最终会调用到 DomainParticipantImpl对象 的enable函数,就是启动participant,pdp发现协议模块等

1.1DomainParticipant的初始化

这里我们先从DomainParticipant::enable入手,来看一下dds 内部是如何运行的。

ini 复制代码
 ReturnCode_t DomainParticipant::enable()
 {
     if (enable_)
    {
         return ReturnCode_t::RETCODE_OK;
    }
 ​
     enable_ = true;
     ReturnCode_t ret_code = impl_->enable();
     enable_ = !!ret_code;
     return ret_code;
 }

DomainParticipant::enable 调用了DomainParticipantImpl::enable函数

php 复制代码
 ReturnCode_t DomainParticipantImpl::enable()
 {
 ······   
     // If DEFAULT_ROS2_MASTER_URI is specified then try to create default client if
     // that already exists.
     RTPSParticipant* part = RTPSDomainImpl::clientServerEnvironmentCreationOverride(
         domain_id_,
         false,
         rtps_attr,
         &rtps_listener_);
 ​
     if (part == nullptr)
    {
         part = RTPSDomain::createParticipant(domain_id_, false, rtps_attr, &rtps_listener_);
 ······        
    }
     ······
     return ReturnCode_t::RETCODE_OK;
 }

这里面RTPSDomainImpl::clientServerEnvironmentCreationOverride函数创建了一个RTPSParticipant的对象。

1.2 fastdds的发现协议

这里简单介绍一下fastdds 中发现协议的种类,后面会用到

发现协议一共有4种,

  1. simple,这是默认的发现协议,包括pdp,edp阶段
  2. static,静态发现协议,有pdp阶段,但是跳过了edp阶段,需要提前设定每个DataReader,DataWriter的IP地址和端口号,需要提前知道topic等信息,代码或者xml 配置,手动配置edp
  3. client-server,就是在节点中区分,client 节点和 server节点,以server节点为中心建立传输网络
  4. manual,没有pdp edp阶段,用户自己设计提前把网组好,写到xml配置里面或者代码配置

每个participant 都需要配置一个参数DiscoveryProtocol,我们看一下这个参数的细节:

arduino 复制代码
 typedef enum DiscoveryProtocol
 {
     NONE,
     /*!<
         NO discovery whatsoever would be used.
         Publisher and Subscriber defined with the same topic name would NOT be linked.
         All matching must be done manually through the addReaderLocator, addReaderProxy, addWriterProxy methods.
      */
     SIMPLE,
     /*!<
         Discovery works according to 'The Real-time Publish-Subscribe Protocol(RTPS) DDS
         Interoperability Wire Protocol Specification'
      */
     EXTERNAL,
     /*!<
         A user defined PDP subclass object must be provided in the attributes that deals with the discovery.
         Framework is not responsible of this object lifetime.
      */
     CLIENT, /*!< The participant will behave as a client concerning discovery operation.
                  Server locators should be specified as attributes. */
     SERVER, /*!< The participant will behave as a server concerning discovery operation.
                  Discovery operation is volatile (discovery handshake must take place if shutdown). */
     BACKUP,  /*!< The participant will behave as a server concerning discovery operation.
                  Discovery operation persist on a file (discovery handshake wouldn't repeat if shutdown). */
     SUPER_CLIENT  /*!< The participant will behave as a client concerning all internal behaviour.
                      Remote servers will treat it as a server and will share every discovery information. */
 ​
 } DiscoveryProtocol_t;

DiscoveryProtocol 的 这几种类型,表明这个participant 在发现协议中所处的角色

  1. NONE //可以手动配置的
  2. SIMPLE //default
  3. EXTERNAL 扩展的,这块没有定义
  4. CLIENT 就是client-server 中的client
  5. SERVER 就是client-server 中的server
  6. BACKUP就是client-server 中的server,可以将发现的节点信息写入数据库中
  7. SUPER_CLIENT就是client-server 中的client,但是被一些节点当成server

上面图就是simple 的 发现机制,各个节点是不做区分

上面图就是server client 形式的连接关系

1.3创建RTPSParticipant

arduino 复制代码
 RTPSParticipant* RTPSDomainImpl::clientServerEnvironmentCreationOverride(
         uint32_t domain_id,
         bool enabled,
         const RTPSParticipantAttributes& att,
         RTPSParticipantListener* listen)
 {
     // Check the specified discovery protocol: if other than simple it has priority over ros environment variable
     if (att.builtin.discovery_config.discoveryProtocol != DiscoveryProtocol_t::SIMPLE)
    {
         EPROSIMA_LOG_INFO(DOMAIN, "Detected non simple discovery protocol attributes."
                 << " Ignoring auto default client-server setup.");
         return nullptr;
    }
 ​
     // We only make the attributes copy when we are sure is worth
     // Is up to the caller guarantee the att argument is not modified during the call
     RTPSParticipantAttributes client_att(att);
 ​
     // Retrieve the info from the environment variable
     RemoteServerList_t& server_list = client_att.builtin.discovery_config.m_DiscoveryServers;
     if (load_environment_server_info(server_list) && server_list.empty())
    {
         // it's not an error, the environment variable may not be set. Any issue with environment
         // variable syntax is EPROSIMA_LOG_ERROR already
         return nullptr;
    }
 ​
     // check if some server requires the UDPv6 transport
     for (auto& server : server_list)
    {
         if (server.requires_transport<LOCATOR_KIND_UDPv6>())
        {
             // extend builtin transports with the UDPv6 transport
             auto descriptor = std::make_shared<fastdds::rtps::UDPv6TransportDescriptor>();
             descriptor->sendBufferSize = client_att.sendSocketBufferSize;
             descriptor->receiveBufferSize = client_att.listenSocketBufferSize;
             client_att.userTransports.push_back(std::move(descriptor));
             break;
        }
    }
 ​
     EPROSIMA_LOG_INFO(DOMAIN, "Detected auto client-server environment variable."
             << "Trying to create client with the default server setup: "
             << client_att.builtin.discovery_config.m_DiscoveryServers);
 ​
     client_att.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol_t::CLIENT;
     // RemoteServerAttributes already fill in above
 ​
     RTPSParticipant* part = createParticipant(domain_id, enabled, client_att, listen);
     if (nullptr != part)
    {
         // client successfully created
         EPROSIMA_LOG_INFO(DOMAIN, "Auto default server-client setup. Default client created.");
         part->mp_impl->client_override(true);
         return part;
    }
 ​
     // unable to create auto server-client default participants
     EPROSIMA_LOG_ERROR(DOMAIN, "Auto default server-client setup. Unable to create the client.");
     return nullptr;
 }

这个函数判断一下使用的发现协议类型,发现协议是server-client,就做一些处理。server-client 协议应用在一些特殊场景,现阶段我们主要针对simple 协议做源码分析。

之后的源码解析都是围绕simple 来展开的,我们通过simple 能大致了解fastdds的发现的大致流程,simple 是默认的用法,我们第一篇中讲的例子就是默认使用simple,server-client 在某些特定场景下会有使用。

所以RTPSDomainImpl::clientServerEnvironmentCreationOverride,返回了一下nullptr,最终会调用到RTPSDomain::createParticipant函数

arduino 复制代码
 RTPSParticipant* RTPSDomain::createParticipant(
         uint32_t domain_id,
         bool enabled,
         const RTPSParticipantAttributes& attrs,
         RTPSParticipantListener* listen)
 {
     return RTPSDomainImpl::createParticipant(domain_id, enabled, attrs, listen);
 }

RTPSDomain::createParticipant调用到RTPSDomainImpl::createParticipant函数

arduino 复制代码
 RTPSParticipant* RTPSDomainImpl::createParticipant(
         uint32_t domain_id,
         bool enabled,
         const RTPSParticipantAttributes& attrs,
         RTPSParticipantListener* listen)
 {
     
 ​
     RTPSParticipantAttributes PParam = attrs;
 // 检测参数
     // 就读取配置文件
   ······
     uint32_t ID;
     // 分配 participant_id
     if (!instance->prepare_participant_id(PParam.participantID, ID))
    {
         return nullptr;
    }
     ······
     PParam.participantID = ID;
 ​
     // Generate a new GuidPrefix_t
     GuidPrefix_t guidP;
     guid_prefix_create(instance->get_id_for_prefix(ID), guidP);
     
 ······
     //new 一个RTPSParticipant
     RTPSParticipant* p = new RTPSParticipant(nullptr);
     RTPSParticipantImpl* pimpl = nullptr;
 ​
     // If we force the participant to have a specific prefix we must define a different persistence GuidPrefix_t that
     // would ensure builtin endpoints are able to differentiate between a communication loss and a participant recovery
   // new 一个RTPSParticipantImpl
     if (PParam.prefix != c_GuidPrefix_Unknown)
    {
         pimpl = new RTPSParticipantImpl(domain_id, PParam, PParam.prefix, guidP, p, listen);
    }
     else
    {
         pimpl = new RTPSParticipantImpl(domain_id, PParam, guidP, p, listen);
    }
 ​
     // Check implementation was correctly initialized
     ······
 ​
     // Above constructors create the sender resources. If a given listening port cannot be allocated an iterative
     // mechanism will allocate another by default. Change the default listening port is unacceptable for
     // discovery server Participant.
     ······检测参数
 ​
     // Check there is at least one transport registered.
     ······
 //将RTPSParticipant ,RTPSParticipantImpl 配对存入RTPSDomain的 m_RTPSParticipants 中去
    {
         std::lock_guard<std::mutex> guard(instance->m_mutex);
         instance->m_RTPSParticipants.push_back(t_p_RTPSParticipant(p, pimpl));
         instance->m_RTPSParticipantIDs[ID].used = true;
         instance->m_RTPSParticipantIDs[ID].reserved = true;
    }
 ​
     // Check the environment file in case it was modified during participant creation leading to a missed callback.
     ······
 ​
     if (enabled)
    {
         // Start protocols
         pimpl->enable();
    }
     return p;
 }

//这个函数主要干了这几件事

1.读取配置文件

2.分配participant id

3.根据participant id分配guid(上一篇中我们讲过guid 是dds 系统中Entity的唯一标识)

4.创建RTPSParticipant

5.创建RTPSParticipantImpl

6.将 RTPSParticipant ,RTPSParticipantImpl 配对存入RTPSDomain的 m_RTPSParticipants 中去

7.调用RTPSParticipantImpl的enable函数

这里面有大量检测参数的工作,这边不详细解读了。

1.4时序图

sequenceDiagram participant DomainParticipant participant DomainParticipantImpl participant RTPSDomain participant RTPSParticipantImpl DomainParticipant ->> DomainParticipantImpl: 1.enable DomainParticipantImpl ->> DomainParticipantImpl: 2.clientServerEnvironmentCreationOverride DomainParticipantImpl ->> RTPSDomain: 3.createParticipant DomainParticipantImpl ->> RTPSParticipantImpl: 4.new RTPSParticipantImpl DomainParticipantImpl ->> RTPSParticipantImpl: 5.enable
  1. DomainParticipant对象的enable函数调用了DomainParticipantImpl的enable函数

    DomainParticipantImpl的enable函数干了2件事情

    a.调用了Domain的static 函数 clientServerEnvironmentCreationOverride 见2

    b.调用了createParticipant函数 见3

  2. clientServerEnvironmentCreationOverride 这个主要是处理client-server 相关逻辑

    如果2创建的RTPSParticipant为空,调用RTPSDomain::crteateParticipant,创建RTPSParticipant

  3. RTPSDomain::crteateParticipant主要干了这几件事情:

    a.检测参数 读取配置文件

    b. 生成participantid

    c.生成GuidPrefix,属于一个participant的entity有相同的GuidPrefix

    d.new 了一个RTPSParticipant

    e.见4

    f.见5

  4. 基于RTPSParticipant,new了一个RTPSParticipantImpl,RTPSParticipant和RTPSParticipantImpl是一一对应关系

    见 RTPSParticipantImpl 的章节

  5. 调用RTPSParticipantImpl的enable

其中步骤1-4 是创建RTPSParticipantImpl

后续2,3,4,5篇会介绍RTPSParticipantImpl的创建

5.enable 是相当于启动RTPSParticipant 的发现机制,之后介绍这块内容。

1.5类图

classDiagram DomainParticipant *-- DomainParticipantImpl DomainParticipantImpl *-- RTPSParticipant RTPSDomain *-- RTPSParticipant RTPSParticipant *-- RTPSParticipantImpl class DomainParticipant { +DomainParticipantImpl* impl_ } class DomainParticipantImpl { +fastrtps::rtps::RTPSParticipant* rtps_participant_ } class RTPSParticipant { } class RTPSParticipantImpl { +RTPSParticipant* mp_userParticipant } class RTPSDomain { +std::vector> m_RTPSParticipants }

RTPSDomain类 有一个全局的vector,m_RTPSParticipants 存放所有的RTPSParticipant对象

所以DomainParticipantImpl和RTPSParticipant是一一对应的关系,而RTPSDomain可以包含多个RTPSParticipant。

这里面DomainParticipantImpl 在DCPS(Data-Centric Publish -subscribe)域,我们简称dds层就是上一篇我们讲到的fastdds 两层结构的上面那层,而RTPSDomain 和 RTPSParticipant是两层结构的下面这一层。

2.RTPSParticipantImpl 的初始化

我们这儿详细解读一下

RTPSParticipantImpl 初始化函数

arduino 复制代码
 RTPSParticipantImpl::RTPSParticipantImpl(
         uint32_t domain_id,
         const RTPSParticipantAttributes& PParam,
         const GuidPrefix_t& guidP,
         const GuidPrefix_t& persistence_guid,
         RTPSParticipant* par,
         RTPSParticipantListener* plisten)
    : domain_id_(domain_id)
    , m_att(PParam)
    , m_guid(guidP, c_EntityId_RTPSParticipant)
    , mp_builtinProtocols(nullptr)
    , mp_ResourceSemaphore(new Semaphore(0))
    , IdCounter(0)
    , type_check_fn_(nullptr)
    , client_override_(false)
    , internal_metatraffic_locators_(false)
    , internal_default_locators_(false)
 #if HAVE_SECURITY
    , m_security_manager(this)
 #endif // if HAVE_SECURITY
    , mp_participantListener(plisten)
    , mp_userParticipant(par)
    , mp_mutex(new std::recursive_mutex())
    , is_intraprocess_only_(should_be_intraprocess_only(PParam))
    , has_shm_transport_(false)
    , match_local_endpoints_(should_match_local_endpoints(PParam))
 {
     if (c_GuidPrefix_Unknown != persistence_guid)
    {
         m_persistence_guid = GUID_t(persistence_guid, c_EntityId_RTPSParticipant);
    }
     // Builtin transports by default
     // 创建transport(udp 和 shm)
     // 使用builtin Transport 用UDPv4TransportDescriptor
     // 默认useBuiltinTransports是true
     // udpv4 是默认的传输   其他的需要配置
     if (PParam.useBuiltinTransports)
    {
         UDPv4TransportDescriptor descriptor;
         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;
        }
         m_network_Factory.RegisterTransport(&descriptor, &m_att.properties);
 ​
 ······
    }
 ​
     // BACKUP servers guid is its persistence one
     // BACKUP servers 会把discover过程中的动作持久化到本地文件中去
     if (PParam.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::BACKUP)
    {
         m_persistence_guid = m_guid;
    }
 ​
     // Store the Guid in string format.
     std::stringstream guid_sstr;
     guid_sstr << m_guid;
     guid_str_ = guid_sstr.str();
 ​
     // Client-server discovery protocol requires that every TCP transport has a listening port
     // Client-server 节点一般都有tcptransport
     switch (PParam.builtin.discovery_config.discoveryProtocol)
    {
         case DiscoveryProtocol::BACKUP:
         case DiscoveryProtocol::CLIENT:
         case DiscoveryProtocol::SERVER:
         case DiscoveryProtocol::SUPER_CLIENT:
             // Verify if listening ports are provided
             for (auto& transportDescriptor : PParam.userTransports)
            {
                 TCPTransportDescriptor* pT = dynamic_cast<TCPTransportDescriptor*>(transportDescriptor.get());
                 if (pT && pT->listening_ports.empty())
                {
                     EPROSIMA_LOG_INFO(RTPS_PARTICIPANT,
                             "Participant " << m_att.getName() << " with GUID " << m_guid <<
                             " tries to use discovery server over TCP without providing a proper listening port.");
                }
            }
         default:
             break;
    }
 ​
     // User defined transports
     // 创建PParam中参数对应的transport,同时设置has_shm_transport_标志位,这里的transport都保存在netwrokfactory中
     // 一个RTPSParticipantImpl 对应一个 netwrokfactory
     for (const auto& transportDescriptor : PParam.userTransports)
    {
         if (m_network_Factory.RegisterTransport(transportDescriptor.get(), &m_att.properties))
        {
             has_shm_transport_ |=
                    (dynamic_cast<fastdds::rtps::SharedMemTransportDescriptor*>(transportDescriptor.get()) != nullptr);
        }
         else
        {
             // SHM transport could be disabled
             if ((dynamic_cast<fastdds::rtps::SharedMemTransportDescriptor*>(transportDescriptor.get()) != nullptr))
            {
                 EPROSIMA_LOG_ERROR(RTPS_PARTICIPANT,
                         "Unable to Register SHM Transport. SHM Transport is not supported in"
                         " the current platform.");
            }
             else
            {
                 EPROSIMA_LOG_ERROR(RTPS_PARTICIPANT,
                         "User transport failed to register.");
            }
 ​
        }
    }
 ​
     mp_userParticipant->mp_impl = this;
     // 初始化ResourceEvent 的thread
     // 这个thread 后面会看到这么用
     // 这个thread 发送定时事件的时候会用到
     mp_event_thr.init_thread();
 
     // 如果没有注册的Transport,就返回
     if (!networkFactoryHasRegisteredTransports())
    {
         return;
    }
 ​
     /* If metatrafficMulticastLocatorList is empty, add mandatory default Locators
        Else -> Take them */
 ​
     // Creation of metatraffic locator and receiver resources
     // 端口号根据 domainid 和 participantID分配
     // port 不一样
     uint32_t metatraffic_multicast_port = m_att.port.getMulticastPort(domain_id_);
     uint32_t metatraffic_unicast_port = m_att.port.getUnicastPort(domain_id_,
                     static_cast<uint32_t>(m_att.participantID));
     uint32_t meta_multicast_port_for_check = metatraffic_multicast_port;
 ​
     /* INSERT DEFAULT MANDATORY MULTICAST LOCATORS HERE */
     if (m_att.builtin.metatrafficMulticastLocatorList.empty() && m_att.builtin.metatrafficUnicastLocatorList.empty())
    {
         // 配置初始值 这里面设置 builtin的multicast 和unicast 的ip
         // builtin 的multicast的ip值,设置为239.255.0.1
         // builtin 的unicast的ip值 设置为0
         get_default_metatraffic_locators();
         internal_metatraffic_locators_ = true;
    }
     else
    {
         //两个不同的进程,不能绑定同一个端口号,单一个进程可以绑定多个端口号
         if (0 < m_att.builtin.metatrafficMulticastLocatorList.size() &&
                 0 !=  m_att.builtin.metatrafficMulticastLocatorList.begin()->port)
        {
             meta_multicast_port_for_check = m_att.builtin.metatrafficMulticastLocatorList.begin()->port;
        }
         //设置port
         std::for_each(m_att.builtin.metatrafficMulticastLocatorList.begin(),
                 m_att.builtin.metatrafficMulticastLocatorList.end(), [&](Locator_t& locator)
                {
                     m_network_Factory.fillMetatrafficMulticastLocator(locator, metatraffic_multicast_port);
                });
         m_network_Factory.NormalizeLocators(m_att.builtin.metatrafficMulticastLocatorList);
 //设置port
         std::for_each(m_att.builtin.metatrafficUnicastLocatorList.begin(),
                 m_att.builtin.metatrafficUnicastLocatorList.end(), [&](Locator_t& locator)
                {
                     m_network_Factory.fillMetatrafficUnicastLocator(locator, metatraffic_unicast_port);
                });
         m_network_Factory.NormalizeLocators(m_att.builtin.metatrafficUnicastLocatorList);
    }
 ​
     // Initial peers
     // initialPeersList 
     if (m_att.builtin.initialPeersList.empty())
    {
         // multicast的ip值,设置为239.255.0.1
         m_att.builtin.initialPeersList = m_att.builtin.metatrafficMulticastLocatorList;
    }
     else
    {
         LocatorList_t initial_peers;
         initial_peers.swap(m_att.builtin.initialPeersList);
 //initial_peers 配置端口号 
         std::for_each(initial_peers.begin(), initial_peers.end(),
                [&](Locator_t& locator)
                {
                     m_network_Factory.configureInitialPeerLocator(domain_id_, locator, m_att);
                });
    }
 ​
     // Creation of user locator and receiver resources
     //If no default locators are defined we define some.
     /* The reasoning here is the following.
        If the parameters of the RTPS Participant don't hold default listening locators for the creation
        of Endpoints, we make some for Unicast only.
        If there is at least one listen locator of any kind, we do not create any default ones.
        If there are no sending locators defined, we create default ones for the transports we implement.
      */
     // 获取非builtin的 unicast_locators 这里ip地址设置为0
     if (m_att.defaultUnicastLocatorList.empty() && m_att.defaultMulticastLocatorList.empty())
    {
         //Default Unicast Locators in case they have not been provided
         /* INSERT DEFAULT UNICAST LOCATORS FOR THE PARTICIPANT */
         // 
         // 获取非builtin的 unicast_locators 这里ip地址设置为0
         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.
         // 设置port
         std::for_each(m_att.defaultUnicastLocatorList.begin(), m_att.defaultUnicastLocatorList.end(),
                [&](Locator_t& loc)
                {
                     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)
                {
                     m_network_Factory.fill_default_locator_port(domain_id_, loc, m_att, true);
                });
    }
 ​
 ······
     // 如果是进程内通信,就清理这些LocatorList
     if (is_intraprocess_only())
    {
         m_att.builtin.metatrafficUnicastLocatorList.clear();
         m_att.defaultUnicastLocatorList.clear();
         m_att.defaultMulticastLocatorList.clear();
    }
 ​
     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);
 ​
     namespace ExternalLocatorsProcessor = fastdds::rtps::ExternalLocatorsProcessor;
     ExternalLocatorsProcessor::set_listening_locators(m_att.builtin.metatraffic_external_unicast_locators,
             m_att.builtin.metatrafficUnicastLocatorList);
     ExternalLocatorsProcessor::set_listening_locators(m_att.default_external_unicast_locators,
             m_att.defaultUnicastLocatorList);
 ​
     // Check metatraffic multicast port
     if (0 < m_att.builtin.metatrafficMulticastLocatorList.size() &&
             m_att.builtin.metatrafficMulticastLocatorList.begin()->port != meta_multicast_port_for_check)
    {
       // 创建ReceiverResources的时候,port号被其他应用占用,可能导致无法无法被发现
         EPROSIMA_LOG_WARNING(RTPS_PARTICIPANT,
                 "Metatraffic multicast port " << meta_multicast_port_for_check << " cannot be opened."
                 " It may is opened by another application. Discovery may fail.");
    }
 ​
     bool allow_growing_buffers = m_att.allocation.send_buffers.dynamic;
     size_t num_send_buffers = m_att.allocation.send_buffers.preallocated_number;
     if (num_send_buffers == 0)
    {
         // Two buffers (user, events)
         // 默认是2个
         num_send_buffers = 2;
         // Add one buffer per reception thread
         num_send_buffers += m_receiverResourcelist.size();
    }
 ​
     // Create buffer pool
     send_buffers_.reset(new SendBuffersManager(num_send_buffers, allow_growing_buffers));
     send_buffers_->init(this);
 ​
     // Initialize flow controller factory.
     // This must be done after initiate network layer.
     // 初始化固有的4个
     flow_controller_factory_.init(this);
 ​
     // Support old API
     // 不是默认的数值,就自己自定义一个flow_controller
     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.
     //
     for (auto flow_controller_desc : m_att.flow_controllers)
    {
         flow_controller_factory_.register_flow_controller(*flow_controller_desc.get());
    }
 ​
 ······
 ​
     mp_builtinProtocols = new BuiltinProtocols();
 ​
     // Initialize builtin protocols
     if (!mp_builtinProtocols->initBuiltinProtocols(this, m_att.builtin))
    {
         EPROSIMA_LOG_ERROR(RTPS_PARTICIPANT, "The builtin protocols were not correctly initialized");
         return;
    }
 ​
     if (c_GuidPrefix_Unknown != persistence_guid)
    {
         EPROSIMA_LOG_INFO(RTPS_PARTICIPANT,
                 "RTPSParticipant "" << m_att.getName() << "" with guidPrefix: " << m_guid.guidPrefix
                                      << " and persistence guid: " << persistence_guid);
    }
     else
    {
         EPROSIMA_LOG_INFO(RTPS_PARTICIPANT,
                 "RTPSParticipant "" << m_att.getName() << "" with guidPrefix: " << m_guid.guidPrefix);
    }
 ​
     initialized_ = true;
 }

这段代码主要干了这5件事情:

graph TD A(Transport 的初始化)-->B(mp_event_thr初始化) B-->c(createReceiverResources) c-->d(flow_controller_factory_) d-->e(BuiltinProtocols的初始化)
  1. Transport 的初始化和注册代码37-114行

  2. mp_event_thr.init_thread() 代码112行

    这个mp_event_thr线程监控这个RTPSParticipant 中所有的TimedEvent

  3. createReceiverResources的相关处理

    分为4大块

    a.代码114-169行,builtin.metatrafficMulticastLocatorList,builtin多播默认地址和端口号的配置,

    builtin.metatrafficUnicastLocatorList,builtin单播默认地址,端口号

    b.代码172-188行,initialpeer 的处理

    c.代码199-237行,defaultUnicastLocatorList单播默认的地址,端口号的配置,defaultMulticastLocatorList多播默认地址和端口号的配置

    defaultUnicastLocatorList 和builtin.metatrafficUnicastLocatorList 的区别:

    builtin.metatrafficMulticastLocatorList,builtin.metatrafficUnicastLocatorList是participant 内置的writer reader的Locator(ip地址和端口),而defaultUnicastLocatorList,defaultMulticastLocatorList是上层应用的writer,reader这些就是上层应用的端点的Locator(ip地址和端口)。

    d.代码239-242行,createReceiverResources 函数调用

  4. 代码278-296行,flow_controller_factory_的相关处理

  5. 代码300-307行,BuiltinProtocols的初始化

相关推荐
QQ_AHAO9 小时前
Drools开源业务规则引擎(一)- 安装与介绍
java·开源·规则引擎·drools·brms
辣码甄源17 小时前
清新简约之美,开源个人博客:Jekyll Theme Chirpy
开源·github
大象机器人20 小时前
使用myCobot280和OAK-D OpenCV DepthAI摄像头制作一个实时脸部跟踪的手机支架!
人工智能·python·opencv·智能手机·机器人·开源·音视频
铁匠匠匠1 天前
django学习入门系列之第四点《案例 登录》
笔记·python·学习·django·开源
邹霍梁@开源软件GoodERP1 天前
【Odoo开源ERP】别把ERP与进销存软件混为一谈
python·开源
FIT2CLOUD飞致云1 天前
MaxKB开源知识库问答系统发布v1.3.0版本,新增强大的工作流引擎
运维·人工智能·开源
openEuler社区2 天前
openEuler 社区 2024 年 5 月运作报告
开源·操作系统·openeuler
腾讯数据架构师2 天前
cube-studio 开源一站式云原生机器学习/深度学习/大模型训练推理平台介绍
机器学习·云原生·开源
敲代码的阳哥shen1616112 天前
抖音矩阵系统源码开发实现功能路径-saas源码开发
矩阵·开源·视频
CSDN官方博客2 天前
走进开源企业 | 湖南大学OpenHarmony技术实训活动在开鸿智谷顺利举办!
开源