3.2 DDS 层-Domain

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

每个域都有一个唯一的标识符,称为 domainId,实现为 uint32 值。共享此 domainId 的应用程序属于同一域,并将能够相互通信。

要将应用程序添加到一个域中,它必须使用相应的 domainId 创建一个 DomainParticipant 实例。DomainParticipant 的实例通过 DomainParticipantFactory 单例创建。

分区在域内引入了另一个实体隔离级别。虽然 DomainParticipant 如果处于同一域中就能够相互通信,但仍可以通过将它们的 Publisher 和 Subscriber 分配到不同的分区来实现隔离。

域类图

3.2.1 DomainParticipant

DomainParticipant 是应用程序进入某个域的入口点。每个 DomainParticipant 从创建时起就与一个单独的域绑定,并包含与该域相关的所有实体。它同时充当 Publisher、Subscriber 和 Topic 的工厂。

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

作为一个实体(Entity),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,它包含在 builtin 的 discovery_config 中(参见《在运行时修改远程服务器列表》)。
在调用 create_participant() 时,如果 Fast DDS 编译时启用了统计支持(默认启用,参见 CMake 选项),则内部的 DomainParticipantQos 可能与输入的 DomainParticipantQos 不同(参见《统计模块设置》)。这意味着希望在 DomainParticipant 创建后进一步修改 DomainParticipantQos 的应用程序应该:

  1. 通过 DomainParticipant::get_qos() 获取内部的 DomainParticipantQos。

  2. 执行所需的修改。

  3. 通过 DomainParticipant::set_qos() 更新 DomainParticipantQos。

有关每个 QosPolicy 类的用法和默认值的更多信息,请参阅其详细说明。

可以使用 DomainParticipant::set_qos() 成员函数修改先前创建的 DomainParticipant 的 QoS 值。尝试在已启用的 DomainParticipant 上修改不可变的 QoS 策略将导致错误。在这种情况下,不会应用任何更改,DomainParticipant 将保持其先前的 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 Default DomainParticipantQos

默认的 DomainParticipantQos 指的是 DomainParticipantFactory 单例的 get_default_participant_qos() 成员函数返回的值。特殊值 PARTICIPANT_QOS_DEFAULT 可以作为 QoS 参数用于 create_participant() 或 DomainParticipant::set_qos() 成员函数,以指示应使用当前的默认 DomainParticipantQos。

当系统启动时,默认的 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 的含义取决于其使用位置:

  • 在 create_participant() 和 DomainParticipant::set_qos() 中,它指的是由 get_default_participant_qos() 返回的默认 DomainParticipantQos。
  • 在 set_default_participant_qos() 中,它指的是默认构造的 DomainParticipantQos()。

3.2.1.2 DomainParticipantExtendedQos

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

可以通过 get_participant_extended_qos_from_profile() 从加载的配置文件中获取此 DomainParticipantExtendedQos,然后使用该 DomainParticipantExtendedQos 创建 DomainParticipant。先前创建的 DomainParticipant 的 QoS 值可以像通过 DomainParticipantQos 创建 DomainParticipant 时那样进行修改。

复制代码
// 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;
}

也可以直接从原始 XML 字符串填充 DomainParticipantExtendedQos 对象,而无需事先加载任何配置文件。更多信息请参阅《从原始 XML 配置文件获取 QoS》部分。

3.2.2 DomainParticipantListener

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

DomainParticipantListener 继承自 TopicListener、PublisherListener 和 SubscriberListener。因此,它能够响应报告给其任何附加实体的各类事件。由于事件总是通知给能够处理该事件的最具体的实体监听器,因此 DomainParticipantListener 从其他监听器继承的回调函数只有在没有其他实体能够处理该事件时才会被调用,这可能是因为该实体没有附加监听器,或者因为该实体上的 StatusMask 禁用了该回调。

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

  • on_participant_discovery():在同一域中发现新的 DomainParticipant、之前已知的 DomainParticipant 已被移除,或某个 DomainParticipant 更改了其 QoS。此方法提供了一个带有额外布尔输出参数的重载,以便发现回调可以通过使用 ignore_participant() 告诉中间件是否应忽略新发现的参与者。当需要在发现回调内部忽略参与者时,应使用此重载,因为在监听器内部调用 ignore_participant() 可能导致死锁。如果两个回调都已实现,则带有 should_be_ignored 布尔标志的发现回调优先。仅当在第一个回调中未忽略(should_be_ignored 参数返回 false)发现的 DomainParticipant 时,第二个发现回调才会执行。
  • on_data_reader_discovery():在同一域中发现新的 DataReader、之前已知的 DataReader 已被移除,或某个 DataReader 更改了其 QoS。
  • on_data_writer_discovery():在同一域中发现新的 DataWriter、之前已知的 DataWriter 已被移除,或某个 DataWriter 更改了其 QoS。
  • onParticipantAuthentication():通知远程 DomainParticipant 的认证过程结果(成功或失败)。
  • should_endpoints_match():在为一对端点(具有兼容 QoS 且在同一主题上的 DataReader 和 DataWriter)评估完标准 QoS 匹配规则后调用。它允许应用程序在标准规则之上应用自定义匹配逻辑作为附加过滤器。回调接收调用监听器的 DomainParticipant、包含读取器信息的 SubscriptionBuiltinTopicData 以及包含写入器信息的 PublicationBuiltinTopicData。返回 true 允许匹配继续进行;返回 false 则阻止匹配。默认实现始终返回 true。

有关回调及其层次结构的更多信息,请参阅《监听器》。

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

    bool should_endpoints_match(
            const DomainParticipant* participant,
            const eprosima::fastdds::rtps::SubscriptionBuiltinTopicData& reader_info,
            const eprosima::fastdds::dds::PublicationBuiltinTopicData& writer_info) override
    {
        static_cast<void>(participant);
        // For example, only allow matching between endpoints belonging to different participants.
        // This prevents intra-participant communication while still allowing
        // cross-participant communication for endpoints that pass standard QoS checks.
        return reader_info.participant_guid.guidPrefix != writer_info.participant_guid.guidPrefix;
    }

};

3.2.3 DomainParticipantFactory

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

DomainParticipantFactory 的行为可以通过在 DomainParticipantFactoryQos 中指定的 QoS 值进行修改。由于 DomainParticipantFactory 是一个单例,其 QoS 只能通过 DomainParticipantFactory::set_qos() 成员函数进行修改。

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

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 是一个单例,其 QoS 只能通过 DomainParticipantFactory::set_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 文件加载配置文件

要基于 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 创建 DomainParticipant

DomainParticipant 的创建是通过 DomainParticipantFactory 单例的 create_participant() 成员函数完成的,该函数充当 DomainParticipant 的工厂。然后,当参与者的生命周期结束时,每个参与者必须使用 delete_participant() 删除。有关删除参与者的更多详细信息,请参阅《删除 DomainParticipant》。

必需参数如下:

  • 标识将在其中创建 DomainParticipant 的域的 DomainId。
  • 描述 DomainParticipant 行为的 DomainParticipantQos。如果提供的值为 PARTICIPANT_QOS_DEFAULT,则使用 DomainParticipantQos 的值。

或者,您可以使用以下内容代替上述两个必需参数:

  • 包含 DomainId 和 DomainParticipantQos 的 DomainParticipantExtendedQos。

可选参数如下:

  • 一个派生自 DomainParticipantListener 的监听器,实现了为响应 DomainParticipant 上的事件和状态变化而触发的回调函数。默认情况下使用空回调函数。
  • 一个 StatusMask,用于激活或停用 DomainParticipantListener 上各个回调的触发。

根据 DDSI-RTPS V2.2 标准(第 9.6.1.1 节),默认端口是根据 DomainId 计算的,如《公认端口》部分所述。因此,建议使用低于 200 的 DomainId(当 DomainId 超过 233 时,默认端口分配将持续失败)。

如果在操作期间发生错误,例如提供的 QoS 不兼容或不受支持,create_participant() 将返回空指针。建议检查返回的值是否是一个有效的指针。

复制代码
// 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 创建

除了使用 DomainParticipantQos,还可以通过 DomainParticipantFactory 单例的 create_participant_with_profile() 成员函数,使用配置文件的名称来创建 DomainParticipant。

必需参数如下:

  • 标识将在其中创建 DomainParticipant 的域的 DomainId。不要使用高于 200 的 DomainId(参见《创建 DomainParticipant》)。
  • 要应用于 DomainParticipant 的配置文件名称。

可选参数如下:

  • 一个派生自 DomainParticipantListener 的监听器,实现了为响应 DomainParticipant 上的事件和状态变化而触发的回调函数。默认情况下使用空回调函数。
  • 一个 StatusMask,用于激活或停用 DomainParticipantListener 上各个回调的触发。默认情况下所有事件都是启用的。

如果在操作期间发生错误,例如提供的 QoS 不兼容或不受支持,create_participant_with_profile() 将返回空指针。建议检查返回的值是否是一个有效的指针。

XML 配置文件必须事先已加载。参见《从 XML 文件加载配置文件》。

复制代码
// 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 创建

如果环境中已导出了一个配置文件(相关信息请参阅《XML 配置文件》),则使用 DomainParticipantFactory 单例的 create_participant_with_default_profile() 成员函数创建 DomainParticipant 时,将使用该配置文件中的设置来配置参与者。如果尚未导出配置文件,则 DomainParticipant 将使用 DomainParticipantQos 的默认值创建,且 DomainId 为 0。

可选参数如下:

  • 一个派生自 DomainParticipantListener 的监听器,实现了为响应 DomainParticipant 上的事件和状态变化而触发的回调函数。默认情况下使用空回调函数。
  • 一个 StatusMask,用于激活或停用 DomainParticipantListener 上各个回调的触发。默认情况下所有事件都是启用的。

如果在操作期间发生错误,create_participant_with_default_profile() 将返回空指针。建议检查返回的值是否是一个有效的指针。

XML 配置文件必须事先已加载。参见《XML 配置文件》。

复制代码
// 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 删除 DomainParticipant

DomainParticipant 应通过 DomainParticipantFactory 单例的 delete_participant() 成员函数进行删除。

只有当属于该参与者的所有实体(Publisher、Subscriber 或 Topic)都已被删除时,才能删除 DomainParticipant。否则,该函数将报错,且 DomainParticipant 不会被删除。这可以通过使用 DomainParticipant 的 delete_contained_entities() 成员函数来完成,也可以通过 DomainParticipant 相应的 delete_ 方法(例如 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(分区)

分区在域引入的物理隔离内部引入了逻辑实体隔离级别的概念。它们代表了在域和主题之外分离发布者和订阅者的另一个层级。为了使发布者与订阅者进行通信,它们必须至少属于一个共同的分区。从这个意义上说,分区代表了一种提供端点间数据分离的轻量级机制:

  • 与域和主题不同,分区可以在端点的生命周期内动态更改,且成本很低。具体来说,不会启动新线程,不会分配新内存,也不会影响更改历史记录。请注意,修改端点的分区成员资格将触发新 QoS 配置的通告,因此,根据新的分区配置,可能会发生新的端点匹配。由于远程端点的匹配,内存分配和运行线程可能会发生变化。
  • 与域和主题不同,一个端点可以同时属于多个分区。对于要在不同主题上共享的某些数据,每个主题必须有一个不同的发布者,每个发布者共享其自己的变更历史记录。另一方面,一个发布者可以使用单个主题数据变更,通过不同分区共享相同的数据,从而减少网络负载。

端点的分区成员资格可以在 PublisherQos 或 SubscriberQos 对象的 PartitionQosPolicy 数据成员上进行配置。该成员保存一个分区名称字符串列表。在 DDS 中,默认分区名称为空字符串 ""。因此,空列表 ({}) 等价于仅包含空字符串的列表 ({""})。因此,未指定分区的发布者和订阅者仍然可以通过默认分区进行通信,而显式配置 "" 也具有相同的行为。如果 "" 与其他名称一起包含在内,则该端点属于默认分区和那些额外分区。

分区与端点相关联,而不是与变更相关联。这意味着端点历史记录对分区的修改不敏感。例如,如果发布者切换分区,之后需要再次重新发送某个较旧的变更,它将把该变更传递到新的分区集,而不管该变更创建时定义的是哪些分区。这意味着一个较晚加入的订阅者可能会接收到在另一组分区处于活动状态时创建的变更。

3.2.5.1 分区中的通配符

分区名称条目可以包含通配符,遵循 POSIX fnmatch API(1003.2-1992 第 B.6 节)定义的命名约定。包含通配符的条目可以匹配多个名称,使端点能够轻松地包含在多个分区中。根据 fnmatch 的规则,两个包含通配符的分区名称只要其中一个匹配另一个,它们就会匹配。也就是说,匹配是双向检查的。例如,考虑以下配置:

  • 一个发布者,其分区为 part。
  • 一个订阅者,其分区为 partition。

尽管 partition 不匹配 part,但此发布者和订阅者仍能相互通信,因为 part 匹配 partition。

请注意,名称为 的分区将匹配任何其他分区,包括默认分区 ""。

3.2.5.2 完整示例

给定一个具有以下分区配置的系统:

|---------------|---------|--------------------------------|
| Participant_1 | Pub_11 | {"Partition_1", "Partition_2"} |
| Participant_1 | Pub_12 | {"*"} |
| Participant_2 | Pub_21 | {default} ≡ {""} ≡ {} |
| Participant_2 | Pub_22 | {"Partition*"} |
| Participant_3 | Subs_31 | {"Partition_1"} |
| Participant_3 | Subs_32 | {"Partition_2"} |
| Participant_3 | Subs_33 | {"Partition_3"} |
| Participant_3 | Subs_34 | {default} ≡ {""} ≡ {} |

端点最终将匹配下表中描述的分区。

|-------------|--------|--------|--------|---------|---------|---------|---------|---|
| Participant_1 || Participant_2 || Participant_3 ||||
| Pub_11 | Pub_12 | Pub_21 | Pub_22 | Subs_31 | Subs_32 | Subs_33 | Subs_34 |
| Partition_1 | ✓ | ✓ | ✕ | ✓ | ✓ | ✕ | ✕ | ✕ |
| Partition_2 | ✓ | ✓ | ✕ | ✓ | ✕ | ✓ | ✕ | ✕ |
| Partition_3 | ✕ | ✓ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ |
| {default} | ✕ | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✓ |

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

|---------------|---------|--------|--------|---|---|
| Participant_1 || Participant_2 ||
| Pub_11 | Pub_12 | Pub_21 | Pub_22 |
| Participant_3 | Subs_31 | ✓ | ✓ | ✕ | ✓ |
| Participant_3 | Subs_32 | ✓ | ✓ | ✕ | ✓ |
| Participant_3 | Subs_33 | ✕ | ✓ | ✕ | ✓ |
| Participant_3 | 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
相关推荐
sdm0704272 小时前
Linux-库制作与原理
linux·c++·操作系统
凌冰_2 小时前
异常: Can not set java.lang.Double field org.hlx.my2.pojo.Book.price
java·开发语言
遇见你...3 小时前
B02 SpringMVC的请求和相应
java·开发语言
Yu_Lijing3 小时前
基于C++的《Head First设计模式》笔记——访问者模式
c++·笔记·设计模式
计算机安禾3 小时前
【数据结构与算法】第20篇:二叉树的链式存储与四种遍历(前序、中序、后序、层序)
c语言·开发语言·数据结构·c++·学习·算法·visual studio
顶点多余3 小时前
POSIX信号量+生产消费模型应用+环形缓冲区实现
linux·c++
_MyFavorite_3 小时前
JAVA重点基础、进阶知识及易错点总结(17)线程安全 & synchronized 同步锁
java·开发语言·安全
_MyFavorite_3 小时前
JAVA重点基础、进阶知识及易错点总结(13)File 类 + 路径操作
java·开发语言