FastDDS:第三节(3.2小节)

发布于:2025-09-05 ⋅ 阅读:(25) ⋅ 点赞:(0)

3.2. 域(Domain)

3.2.1.域参与者(DomainParticipant)

3.2.1.1.域参与者服务质量(DomainParticipantQos)

3.2.1.1.1.默认DomainParticipantQos

3.2.1.2.域参与者扩展服务质量(DomainParticipantExtendedQos)

3.2.2.域参与者监听器(DomainParticipantListener)

3.2.3.域参与者工厂(DomainParticipantFactory)

3.2.3.1.域参与者工厂服务质量(DomainParticipantFactoryQos)

3.2.3.2.从 XML 文件加载配置文件(Loading profiles from an XML file)

3.2.4.创建域参与者(Creating a DomainParticipant)

3.2.4.1.基于配置文件创建DomainParticipant(Profile based creation of a DomainParticipant)

3.2.4.2.默认配置文件DomainParticipant创建(Default profile DomainParticipant creation)

3.2.4.3.删除域参与者(Deleting a DomainParticipant)

3.2.5.分区(Partitions)

3.2.5.1.分区中的通配符(Wildcards in Partitions)

3.2.5.2.完整示例(Full example)


3.2. 域(Domain)

域代表一个独立的通信平面。它在共享通信基础架构的实体之间建立逻辑隔离。从概念上讲,它可以被视为一个虚拟网络,连接同一域中运行的所有应用程序,并将它们与不同域中运行的应用程序隔离。这样,多个独立的分布式应用程序就可以在同一个物理网络中共存,互不干扰,甚至彼此不感知。

每个域都有一个唯一的标识符,称为 domainId,它以值的形式实现uint32​。共享此 domainId 的应用程序属于同一个域,并且能够进行通信。

要将应用程序添加到域,它必须使用适当的 domainId 创建DomainParticipant实例。DomainParticipant 实例是通过DomainParticipantFactory单例创建的。

分区在域内引入了另一个实体隔离级别。虽然 DomainParticipant 在同一个域中可以相互通信,但仍然可以隔离它们的发布者订阅者,并将它们分配到不同的分区


3.2.1.域参与者(DomainParticipant)

DomainParticipant是应用程序进入域的入口点。每个DomainParticipant从创建之初就链接到一个域,并包含与该域相关的所有实体。它还充当PublisherSubscriberTopic的工厂。

可以使用 DomainParticipantQos 上指定的 QoS 值来修改 DomainParticipant 的行为。QoS 值可以在创建 DomainParticipant 时设置,也可以稍后使用DomainParticipant::set_qos()​成员函数进行修改。

作为一个实体,DomainParticipant 接受一个DomainParticipantListener,该监听器将收到有关 DomainParticipant 实例的状态变化的通知。

3.2.1.1.域参与者服务质量(DomainParticipantQos)

DomainParticipantQos​控制DomainParticipant的行为。它内部包含以下QosPolicy​对象:

QosPolicy class Accessor/Mutator Mutable
UserDataQosPolicy user_data() Yes
EntityFactoryQosPolicy entity_factory() Yes
ParticipantResourceLimitsQos allocation() No
PropertyPolicyQos properties() No
WireProtocolConfigQos wire_protocol() No*
TransportConfigQos transport()​ and setup_transports() No
FlowControllersQos flow_controllers() No
ThreadSettings builtin_controllers_sender_thread() No
ThreadSettings timed_events_thread() No
ThreadSettings discovery_server_thread() No
ThreadSettings typelookup_service_thread() No
ThreadSettings security_log_thread() No

WireProtocolConfigQos中唯一可变的字段是m_DiscoveryServers​,它包含discovery_config​在内builtin​(请参阅在运行时修改远程服务器列表)。

调用create_participant()​时,如果 Fast DDS 使用statistics support进行编译(默认启用,请参阅CMake 选项),则内部DomainParticipantQos​可能与输入DomainParticipantQos​不同(请参阅统计模块设置DomainParticipantQos​)。这意味着,如果应用程序希望在创建后进一步修改 ,DomainParticipant​则应该:

  1. DomainParticipantQos​通过检索内部的方式DomainParticipant::get_qos()​获取。
  2. 明确所需的修改。
  3. DomainParticipantQos​通过DomainParticipant::set_qos()​来更新。

先前创建的域参与者(DomainParticipant)的服务质量(QoS)值可以通过 DomainParticipant::set_qos() 成员函数进行修改。

试图修改已启用的域参与者上的不可变 QosPolicy 将导致错误。在这种情况下,不会应用任何更改,域参与者将保持其先前的 DomainParticipantQos。

// Create a DomainParticipant with default DomainParticipantQos
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Get the current QoS or create a new one from scratch
DomainParticipantQos qos = participant->get_qos();

// Modify QoS attributes
qos.entity_factory().autoenable_created_entities = false;

// Assign the new Qos to the object
participant->set_qos(qos);

3.2.1.1.1.默认DomainParticipantQos

默认的 DomainParticipantQos 是指DomainParticipantFactoryget_default_participant_qos()​单例上的成员函数返回的值。该特殊值可用作成员函数的 QoS 参数。

系统启动时,默认的 DomainParticipantQos 相当于默认的构造值DomainParticipantQos()​。可以随时使用DomainParticipantFactory 单例上的成员函数set_default_participant_qos()​修改默认的 DomainParticipantQos。修改默认的 DomainParticipantQos 不会影响现有的 DomainParticipant 实例。

// Get the current QoS or create a new one from scratch
DomainParticipantQos qos_type1 = DomainParticipantFactory::get_instance()->get_default_participant_qos();

// Modify QoS attributes
// (...)

// Set as the new default TopicQos
if (DomainParticipantFactory::get_instance()->set_default_participant_qos(qos_type1) !=
        RETCODE_OK)
{
    // Error
    return;
}

// Create a DomainParticipant with the new default DomainParticipantQos.
DomainParticipant* participant_with_qos_type1 =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant_with_qos_type1)
{
    // Error
    return;
}

// Get the current QoS or create a new one from scratch
DomainParticipantQos qos_type2;

// Modify QoS attributes
// (...)

// Set as the new default TopicQos
if (DomainParticipantFactory::get_instance()->set_default_participant_qos(qos_type2) !=
        RETCODE_OK)
{
    // Error
    return;
}

// Create a Topic with the new default TopicQos.
DomainParticipant* participant_with_qos_type2 =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant_with_qos_type2)
{
    // Error
    return;
}

// Resetting the default DomainParticipantQos to the original default constructed values
if (DomainParticipantFactory::get_instance()->set_default_participant_qos(PARTICIPANT_QOS_DEFAULT)
        != RETCODE_OK)
{
    // Error
    return;
}

// The previous instruction is equivalent to the following
if (DomainParticipantFactory::get_instance()->set_default_participant_qos(DomainParticipantQos())
        != RETCODE_OK)
{
    // Error
    return;
}

set_default_participant_qos()​成员函数也接受该值PARTICIPANT_QOS_DEFAULT​作为输入参数。这会将当前默认的 DomainParticipantQos 重置为默认的构造值DomainParticipantQos()​。

// Create a custom DomainParticipantQos
DomainParticipantQos custom_qos;

// Modify QoS attributes
// (...)

// Create a DomainParticipant with a custom DomainParticipantQos

DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0, custom_qos);
if (nullptr == participant)
{
    // Error
    return;
}

// Set the QoS on the participant to the default
if (participant->set_qos(PARTICIPANT_QOS_DEFAULT) != RETCODE_OK)
{
    // Error
    return;
}

// The previous instruction is equivalent to the following:
if (participant->set_qos(DomainParticipantFactory::get_instance()->get_default_participant_qos())
        != RETCODE_OK)
{
    // Error
    return;
}

​PARTICIPANT_QOS_DEFAULT​根据使用位置的不同,该值具有不同的含义:

3.2.1.2.域参与者扩展服务质量(DomainParticipantExtendedQos)

DomainParticipantExtendedQos​是DomainParticipantQos​的扩展,包含DomainId​和DomainParticipantQos​对象。此类有助于简化 DomainParticipant 的创建和配置,因为它允许在单个对象中指定所有必要的设置。

DomainParticipantExtendedQos​可以从已加载的配置文件中获取get_participant_extended_qos_from_profile()​,然后使用 DomainParticipantExtendedQos 创建域参与者。

// Create a DomainParticipant with DomainParticipantExtendedQos from profile
DomainParticipantExtendedQos profile_extended_qos;
DomainParticipantFactory::get_instance()->get_participant_extended_qos_from_profile("participant_profile",
        profile_extended_qos);

DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(profile_extended_qos);
if (nullptr == participant)
{
    // Error
    return;
}

3.2.2.域参与者监听器(DomainParticipantListener)

DomainParticipantListener​是一个抽象类,定义了响应DomainParticipant状态变化时触发的回调。默认情况下,所有这些回调都是空的,不执行任何操作。用户应该实现此类的特化,覆盖应用程序所需的回调。未被覆盖的回调将保持其空的实现。

DomainParticipantListener 继承自TopicListenerPublisherListenerSubscriberListener。因此,它能够对报告给其任何附加实体的各种事件做出反应。由于事件始终会通知给能够处理该事件的最具体的实体监听器,因此,DomainParticipantListener 从其他监听器继承的回调仅在没有其他实体能够处理该事件时才会被调用(因为该实体没有附加监听器,或者因为回调被StatusMask​实体禁用)。

此外,DomainParticipantListener 添加了以下非标准回调:

  • on_participant_discovery()​:在同一个域中发现了一个新的 DomainParticipant,一个先前已知的 DomainParticipant 已被删除,或者某个 DomainParticipant 已更改其 QoS。此方法提供了一个带有附加布尔输出参数的重载,因此发现回调可以告诉中间件是否必须通过使用来忽略新发现的参与者ignore_participant()​。当需要在发现回调中忽略参与者时应该使用此重载,因为ignore_participant()​在侦听器内部调用可能会导致死锁。如果实现了两个回调,则具有布尔标志的发现回调优先。仅当在第一个回调中没有忽略发现的 DomainParticipant(参数返回)should_be_ignored​时,才会执行第二个发现回调。should_be_ignored``false​
  • on_data_reader_discovery()​:在同一个域中发现了新的DataReader,先前已知的 DataReader 已被删除,或者某些 DataReader 已更改其 QoS。
  • on_data_writer_discovery()​:在同一个域中发现了新的DataWriter,先前已知的 DataWriter 已被删除,或者某些 DataWriter 已更改其 QoS。
  • onParticipantAuthentication()​:通知远程 DomainParticipant 的身份验证过程的结果(失败或成功)
class CustomDomainParticipantListener : public DomainParticipantListener
{

public:

    CustomDomainParticipantListener()
        : DomainParticipantListener()
    {
    }

    virtual ~CustomDomainParticipantListener()
    {
    }

    void on_participant_discovery(
            DomainParticipant* participant,
            eprosima::fastdds::rtps::ParticipantDiscoveryStatus status,
            const ParticipantBuiltinTopicData& info,
            bool& should_be_ignored) override
    {
        should_be_ignored = false;
        if (status == eprosima::fastdds::rtps::ParticipantDiscoveryStatus::DISCOVERED_PARTICIPANT)
        {
            std::cout << "New participant discovered" << std::endl;
            // The following line can be modified to evaluate whether the discovered participant should be ignored
            // (usually based on fields present in the discovery information)
            bool ignoring_condition = false;
            if (ignoring_condition)
            {
                should_be_ignored = true; // Request the ignoring of the discovered participant
            }
        }
        else if (status == eprosima::fastdds::rtps::ParticipantDiscoveryStatus::REMOVED_PARTICIPANT ||
                status == eprosima::fastdds::rtps::ParticipantDiscoveryStatus::DROPPED_PARTICIPANT)
        {
            std::cout << "Participant lost" << std::endl;
        }
    }

#if HAVE_SECURITY
    void onParticipantAuthentication(
            DomainParticipant* participant,
            eprosima::fastdds::rtps::ParticipantAuthenticationInfo&& info) override
    {
        if (info.status == eprosima::fastdds::rtps::ParticipantAuthenticationInfo::AUTHORIZED_PARTICIPANT)
        {
            std::cout << "A participant was authorized" << std::endl;
        }
        else if (info.status == eprosima::fastdds::rtps::ParticipantAuthenticationInfo::UNAUTHORIZED_PARTICIPANT)
        {
            std::cout << "A participant failed authorization" << std::endl;
        }
    }

#endif // if HAVE_SECURITY

    void on_data_reader_discovery(
            DomainParticipant* participant,
            eprosima::fastdds::rtps::ReaderDiscoveryStatus reason,
            const eprosima::fastdds::rtps::SubscriptionBuiltinTopicData& info,
            bool& should_be_ignored) override
    {
        should_be_ignored = false;
        if (reason == eprosima::fastdds::rtps::ReaderDiscoveryStatus::DISCOVERED_READER)
        {
            std::cout << "New datareader discovered" << std::endl;
            // The following line can be modified to evaluate whether the discovered datareader should be ignored
            // (usually based on fields present in the discovery information)
            bool ignoring_condition = false;
            if (ignoring_condition)
            {
                should_be_ignored = true; // Request the ignoring of the discovered datareader
            }
        }
        else if (reason == eprosima::fastdds::rtps::ReaderDiscoveryStatus::REMOVED_READER)
        {
            std::cout << "Datareader lost" << std::endl;
        }
    }

    void on_data_writer_discovery(
            DomainParticipant* participant,
            eprosima::fastdds::rtps::WriterDiscoveryStatus reason,
            const eprosima::fastdds::dds::PublicationBuiltinTopicData& info,
            bool& should_be_ignored) override
    {
        static_cast<void>(participant);
        static_cast<void>(info);

        should_be_ignored = false;
        if (reason == eprosima::fastdds::rtps::WriterDiscoveryStatus::DISCOVERED_WRITER)
        {
            std::cout << "New datawriter discovered" << std::endl;
            // The following line can be modified to evaluate whether the discovered datawriter should be ignored
            // (usually based on fields present in the discovery information)
            bool ignoring_condition = false;
            if (ignoring_condition)
            {
                should_be_ignored = true; // Request the ignoring of the discovered datawriter
            }
        }
        else if (reason == eprosima::fastdds::rtps::WriterDiscoveryStatus::REMOVED_WRITER)
        {
            std::cout << "Datawriter lost" << std::endl;
        }
    }

};

3.2.3.域参与者工厂(DomainParticipantFactory)

此类的唯一目的是允许创建和销毁DomainParticipant对象。DomainParticipantFactory​它本身没有工厂,而是一个单例对象,可以通过类get_instance()​上的静态成员函数进行访问DomainParticipantFactory​。

可以使用DomainParticipantFactoryQos上指定的 QoS 值来修改 DomainParticipantFactory 的行为。由于 DomainParticipantFactory 是单例,因此只能使用DomainParticipantFactory::set_qos()​成员函数来修改其 QoS。

DomainParticipantFactory 不接受任何监听器,因为它不是一个实体。

3.2.3.1.域参与者工厂服务质量(DomainParticipantFactoryQos)

DomainParticipantFactoryQos 控制DomainParticipantFactory的行为。它内部包含以下QosPolicy​对象:

QosPolicy class Accessor/Mutator Mutable
EntityFactoryQosPolicy entity_factory() Yes
ThreadSettings shm_watchdog_thread() No
ThreadSettings file_watch_threads() No

由于 DomainParticipantFactory 是单例,因此只能使用DomainParticipantFactory::set_qos()​成员函数来修改其 QoS。

DomainParticipantFactoryQos qos;

// Setting autoenable_created_entities to true makes the created DomainParticipants
// to be enabled upon creation
qos.entity_factory().autoenable_created_entities = true;
if (DomainParticipantFactory::get_instance()->set_qos(qos) != RETCODE_OK)
{
    // Error
    return;
}

// Create a DomainParticipant with the new DomainParticipantFactoryQos.
// The returned DomainParticipant is already enabled
DomainParticipant* enabled_participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == enabled_participant)
{
    // Error
    return;
}

// Setting autoenable_created_entities to false makes the created DomainParticipants
// to be disabled upon creation
qos.entity_factory().autoenable_created_entities = false;
if (DomainParticipantFactory::get_instance()->set_qos(qos) != RETCODE_OK)
{
    // Error
    return;
}

// Create a DomainParticipant with the new DomainParticipantFactoryQos.
// The returned DomainParticipant is disabled and will need to be enabled explicitly
DomainParticipant* disabled_participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == disabled_participant)
{
    // Error
    return;
}

3.2.3.2.从 XML 文件加载配置文件(Loading profiles from an XML file)

要基于 XML 配置文件创建实体,必须首先加载包含此类配置文件的文件。

如果配置文件在默认加载的文件中已有描述,则在初始化时会自动生效。否则,load_XML_profiles_file()​可以使用成员函数加载 XML 文件中的配置文件。有关 XML 配置文件格式和自动加载的更多信息,请参阅XML 配置文件部分。

一旦加载,配置文件的名称可用于创建根据配置文件规范具有 QoS 设置的实体。

// Load the XML with the profiles
DomainParticipantFactory::get_instance()->load_XML_profiles_file("profiles.xml");

// Profiles can now be used to create Entities
DomainParticipant* participant_with_profile =
        DomainParticipantFactory::get_instance()->create_participant_with_profile(0, "participant_profile");
if (nullptr == participant_with_profile)
{
    // Error
    return;
}

3.2.4.创建域参与者(Creating a DomainParticipant)

DomainParticipant的创建是通过DomainParticipantFactory单例的成员函数create_participant()​完成的,该单例充当 DomainParticipant 的工厂。然后,当参与者的生命周期结束时,必须使用delete_participant()​删除所有参与者。

强制参数:

  • DomainId:用于标识将创建 DomainParticipant 的域的标识符。
  • DomainParticipantQos:描述 DomainParticipant 行为的 QoS(服务质量)配置。如果提供的值为 PARTICIPANT_QOS_DEFAULT​,则将使用 DomainParticipantQos 的默认值。

或者,您可以使用以下方法来代替上述两个强制参数:

  • DomainParticipantExtendedQos,它同时包含了 DomainId 和 DomainParticipantQos 的配置信息。

可选参数:

  • 一个从 DomainParticipantListener 派生的 Listener,用于实现回调函数。这些回调函数会在 DomainParticipant 上发生事件或状态变化时被触发。默认情况下,使用的是空实现的回调函数。
  • 一个 StatusMask,用于启用或禁用 DomainParticipantListener 中各个回调函数的触发。通过该参数可以精确控制哪些事件将触发对应的回调逻辑。

按照 DDSI-RTPS V2.2 标准(第 9.6.1.1 节),默认端口号是通过 DomainId 计算得出的,具体方法在“Well Known Ports”一节中有说明。因此,强烈建议使用小于 200 的 DomainId;如果 DomainId 大于或等于 233,默认端口分配将始终失败。

create_participant()​如果操作过程中出现错误(例如,提供的QoS不兼容或不受支持),将返回空指针。建议检查返回值是否为有效指针。

// Create a DomainParticipant with default DomainParticipantQos and no Listener
// The value PARTICIPANT_QOS_DEFAULT is used to denote the default QoS.
DomainParticipant* participant_with_default_attributes =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant_with_default_attributes)
{
    // Error
    return;
}

// A custom DomainParticipantQos can be provided to the creation method
DomainParticipantQos custom_qos;

// Modify QoS attributes
// (...)

DomainParticipant* participant_with_custom_qos =
        DomainParticipantFactory::get_instance()->create_participant(0, custom_qos);
if (nullptr == participant_with_custom_qos)
{
    // Error
    return;
}

// Create a DomainParticipant with default QoS and a custom Listener.
// CustomDomainParticipantListener inherits from DomainParticipantListener.
// The value PARTICIPANT_QOS_DEFAULT is used to denote the default QoS.
CustomDomainParticipantListener custom_listener;
DomainParticipant* participant_with_default_qos_and_custom_listener =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT,
                &custom_listener);
if (nullptr == participant_with_default_qos_and_custom_listener)
{
    // Error
    return;
}

3.2.4.1.基于配置文件创建DomainParticipant(Profile based creation of a DomainParticipant)

在创建 DomainParticipant​ 时,除了使用 DomainParticipantQos​,还可以通过 DomainParticipantFactory​ 单例对象的 create_participant_with_profile()​ 成员函数,使用一个预定义的配置文件名称来创建该对象。

必选参数:

  • DomainId(域ID):用于标识将要创建 DomainParticipant​ 所属的域。

    注意:请不要使用高于 200 的 DomainId(详见“创建 DomainParticipant”相关文档)。

  • Profile名称(配置文件名):指定将应用于该 DomainParticipant​ 的配置文件名称。

可选参数:

  • Listener(监听器):一个从 DomainParticipantListener​ 派生的类实例,用于实现回调函数,以便在 DomainParticipant​ 的事件和状态发生变化时触发相应操作。

    默认情况下使用空的回调函数。

  • StatusMask(状态掩码):用于启用或禁用 DomainParticipantListener​ 中特定回调的触发机制。

    默认情况下,所有事件都是启用状态。

返回值:

  • ​create_participant_with_profile()​ 函数在执行出错时会返回一个空指针,例如当提供的 QoS 不兼容或不被支持时。
  • 建议在使用返回值前检查其是否为有效指针,以避免潜在的运行时错误。
// First load the XML with the profiles
DomainParticipantFactory::get_instance()->load_XML_profiles_file("profiles.xml");

// Create a DomainParticipant using a profile and no Listener
DomainParticipant* participant_with_profile =
        DomainParticipantFactory::get_instance()->create_participant_with_profile(0, "participant_profile");
if (nullptr == participant_with_profile)
{
    // Error
    return;
}

// Create a DomainParticipant using a profile and a custom Listener.
// CustomDomainParticipantListener inherits from DomainParticipantListener.
CustomDomainParticipantListener custom_listener;
DomainParticipant* participant_with_profile_and_custom_listener =
        DomainParticipantFactory::get_instance()->create_participant_with_profile(0, "participant_profile",
                &custom_listener);
if (nullptr == participant_with_profile_and_custom_listener)
{
    // Error
    return;
}

3.2.4.2.默认配置文件DomainParticipant创建(Default profile DomainParticipant creation)

如果环境中已经导出了某个配置文件,那么使用DomainParticipantFactory单例上的create_participant_with_default_profile()​成员函数创建DomainParticipant时,将会依据该配置文件的设置来对该参与者进行配置。如果尚未导出配置文件,那么DomainParticipant将会按照DomainParticipantQos中定义的默认值来创建,并且域ID(DomainId)将被设置为0。

可选参数包括:

  • 一个继承自DomainParticipantListener的监听器,用于实现当DomainParticipant上发生事件或状态改变时所触发的回调函数。默认情况下,这些回调函数为空实现。
  • 一个状态掩码(StatusMask),用于激活或禁用DomainParticipantListener上各个回调函数的触发。默认情况下,所有事件都是启用的。

​create_participant_with_default_profile()​在操作发生错误时将返回一个空指针。因此建议在使用返回值前检查其是否为有效指针。

// Create a DomainParticipant using the environment profile and no Listener
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant_with_default_profile();
if (nullptr == participant)
{
    // Error
    return;
}

// Create a DomainParticipant using the environment profile and a custom Listener.
// CustomDomainParticipantListener inherits from DomainParticipantListener.
CustomDomainParticipantListener custom_listener;
DomainParticipant* participant_with_custom_listener =
        DomainParticipantFactory::get_instance()->create_participant_with_default_profile(
    &custom_listener, StatusMask::none());
if (nullptr == participant_with_custom_listener)
{
    // Error
    return;
}

3.2.4.3.删除域参与者(Deleting a DomainParticipant)

一个 DomainParticipant​ 应当通过调用 DomainParticipantFactory​ 单例对象 上的 delete_participant() ​成员函数来进行删除。

只有在属于该 DomainParticipant 的所有实体(如 Publisher、Subscriber 或 Topic)已经被删除的情况下,才能删除该 DomainParticipant。否则,该函数将报错,并且 DomainParticipant 不会被删除。这一操作可以通过以下两种方式完成:

  • 使用 DomainParticipant 的 delete_contained_entities() 成员函数,一次性删除所有包含的实体;
  • 或者通过 DomainParticipant 提供的相应删除方法,手动逐个删除每个实体,例如 delete_publisher()、delete_subscriber()、delete_topic() 等。
// Create a DomainParticipant
DomainParticipant* participant =
        DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
if (nullptr == participant)
{
    // Error
    return;
}

// Use the DomainParticipant to communicate
// (...)

// Delete entities created by the DomainParticipant
if (participant->delete_contained_entities() != RETCODE_OK)
{
    // DomainParticipant failed to delete the entities it created.
    return;
}

// Delete the DomainParticipant
if (DomainParticipantFactory::get_instance()->delete_participant(participant) != RETCODE_OK)
{
    // Error
    return;
}

3.2.5.分区(Partitions)

分区(Partitions)在由域(Domain)提供的物理隔离基础上引入了一个逻辑实体隔离层级的概念。它们代表了在域和主题(Topic)之外进一步隔离发布者(Publisher)和订阅者(Subscriber)的机制。为了实现发布者与订阅者之间的通信,它们至少需要共享一个共同的分区。从这个意义上讲,分区是一种轻量级机制,用于在端点之间提供数据隔离。

与域和主题不同,分区可以在端点生命周期内动态更改,且代价较小。具体来说,不会启动新线程,不会分配新内存,也不会影响变更历史。需要注意的是,修改端点的分区成员资格将触发新QoS配置的公告,从而可能导致新的端点匹配行为,具体取决于新的分区配置。由于远程端点的匹配行为,可能会发生内存分配或线程运行状态的变化。

与域和主题不同的是,一个端点可以同时属于多个分区。对于需要在不同主题之间共享的数据来说,每个主题都需要一个独立的发布者,每个发布者各自维护其变更历史。而在一个主题下,一个发布者可以通过使用不同的分区共享相同的数据,只需一次数据变更操作即可,从而减少了网络负载。

端点的分区成员资格可以通过配置PublisherQos或SubscriberQos对象中的PartitionQosPolicy数据成员来设定。该成员保存一个分区名称字符串列表。如果某个实体未定义任何分区,则它将自动被归入默认的无名分区。因此,未指定任何分区的发布者和订阅者仍可通过默认的无名分区进行通信。

分区是与端点相关联的,而不是与数据变更(change)相关联的。这意味着端点的历史记录对分区的更改是“无感知”的。例如,如果一个发布者切换了分区,并在之后需要重新发送某些旧的数据变更,它会将这些数据发送到新的分区集合中,而不论该变更生成时处于哪些分区。这表示,一个晚加入的订阅者可能会收到在不同分区配置下产生的变更数据。

3.2.5.1.分区中的通配符(Wildcards in Partitions)

分区名称条目可以包含通配符,遵循 POSIX fnmatch API(IEEE 标准 1003.2-1992 第 B.6 节)所定义的命名规则。带有通配符的条目可以匹配多个名称,从而允许一个端点(endpoint)轻松地被包含在多个分区(Partition)中。当两个分区名称都包含通配符时,只要其中一个能通过 fnmatch 规则匹配另一个,就认为它们是匹配的。也就是说,这种匹配是双向进行的。例如,考虑以下配置:

  • 一个发布者(Publisher)的分区名为 part*​
  • 一个订阅者(Subscriber)的分区名为 partition*​

尽管 partition*​ 并不能匹配 part*​,但这两个发布者和订阅者之间仍然可以通信,因为 part*​ 可以匹配 partition*​。

需要注意的是,名为 *​ 的分区可以匹配任何其他分区,除了默认分区(default Partition)之外。

3.2.5.2.完整示例(Full example)

假设系统具有以下分区配置:

Participant_1 Pub_11 {“Partition_1”, “Partition_2”}
Pub_12 {“*”}
Participant_2 Pub_21 {}
Pub_22 {“Partition*”}
Participant_3 Subs_31 {“Partition_1”}
Subs_32 {“Partition_2”}
Subs_33 {“Partition_3”}
Subs_34 {}

端点最终将与下表所示的分区匹配。请注意,Pub_12与默认分区不匹配。

Participant_1 Participant_2 Participant_3
Pub_11 Pub_12 Pub_21 Pub_22
Partition_1
Partition_2
Partition_3
{default}

下表提供了给定示例的通信矩阵:

Participant_1 Participant_2
Pub_11 Pub_12 Pub_21
Participant_3 Subs_31
Subs_32
Subs_33
Subs_34

下面的代码片段显示了本例中描述的用例所需的参数集。

PublisherQos pub_11_qos;
pub_11_qos.partition().push_back("Partition_1");
pub_11_qos.partition().push_back("Partition_2");

PublisherQos pub_12_qos;
pub_12_qos.partition().push_back("*");

PublisherQos pub_21_qos;
//No partitions defined for pub_21

PublisherQos pub_22_qos;
pub_22_qos.partition().push_back("Partition*");

SubscriberQos subs_31_qos;
subs_31_qos.partition().push_back("Partition_1");

SubscriberQos subs_32_qos;
subs_32_qos.partition().push_back("Partition_2");

SubscriberQos subs_33_qos;
subs_33_qos.partition().push_back("Partition_3");

SubscriberQos subs_34_qos;
//No partitions defined for subs_34
<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com">
    <data_writer profile_name="pub_11">
        <qos>
            <partition>
                <names>
                    <name>Partition_1</name>
                    <name>Partition_2</name>
                </names>
            </partition>
        </qos>
    </data_writer>

    <data_writer profile_name="pub_12">
        <qos>
            <partition>
                <names>
                    <name>*</name>
                </names>
            </partition>
        </qos>
    </data_writer>

    <data_writer profile_name="pub_22">
        <qos>
            <partition>
                <names>
                    <name>Partition*</name>
                </names>
            </partition>
        </qos>
    </data_writer>

    <data_reader profile_name="subs_31">
        <qos>
            <partition>
                <names>
                    <name>Partition_1</name>
                </names>
            </partition>
        </qos>
    </data_reader>

    <data_reader profile_name="subs_32">
        <qos>
            <partition>
                <names>
                    <name>Partition_2</name>
                </names>
            </partition>
        </qos>
    </data_reader>

    <data_reader profile_name="subs_33">
        <qos>
            <partition>
                <names>
                    <name>Partition_3</name>
                </names>
            </partition>
        </qos>
    </data_reader>
</profiles>