FastDDS 源码剖析:DataWriter分析

news2024/10/6 8:30:45

目录

DataWriter分析

DataWriter 类分析

DataWriterImpl 类分析

关键函数分析


DataWriter分析

DataWriter 类分析

DataWriter 类是 Fast DDS 库中的一个重要类,它用于实现 DDS(Data Distribution Service)发布-订阅通信模型中的数据写入功能。

用途:
DataWriter 类用于向特定主题(Topic)发布数据。它负责将数据写入到该主题,并将数据传输给订阅该主题的数据读取器(DataReader)。通过 DataWriter,用户可以发布数据,注册和注销数据实例,获取状态信息以及设置数据写入的 QoS(Quality of Service)。

成员变量:

  • impl_:指向 DataWriterImpl 类的实例的指针,它是 DataWriter 的实际实现。

成员函数:
DataWriter 类提供了多个成员函数,下面是一些重要的函数及其作用:

  • enable():启用数据写入器。
  • write(data):将数据写入到主题。
  • register_instance(instance):注册数据实例。
  • unregister_instance(instance):注销数据实例。
  • get_key_value(key_holder, handle):获取数据实例的键值。
  • set_qos(qos):设置数据写入的 QoS。
  • get_qos():获取当前数据写入的 QoS。
  • set_listener(listener):设置数据写入的监听器。
  • get_topic():获取关联的主题。
  • get_publisher():获取创建该数据写入器的发布者。

大致的实现方法:
DataWriter 类的实现方法主要依赖于底层的 DataWriterImpl 类。DataWriterImpl 类是 DataWriter 的实际实现,它封装了与数据写入相关的底层逻辑和操作。在 DataWriter 的成员函数中,通过调用 DataWriterImpl 对应的成员函数来完成相应的操作。例如,在 write(data) 函数中,会调用 DataWriterImpl 的 write(data) 函数来实际执行数据写入操作。

同时,DataWriter 类还提供了一些其他功能,如通过 loan_sample 和 discard_loan 函数直接在内部池中借用和归还数据样本的功能,以及获取数据写入的状态信息等。

下面是详细的方法描述

因为这个类本质上只是一个包装类,所以重点函数基本上都是DataWriterImpl 类实现的

DataWriterImpl 类分析

类图

DataWriterImpl类是Fast DDS库中的一个关键类,用于实现数据写入的功能。它包含了数据写入相关的操作和状态,以及与底层通信层(RTPS)的交互。下面是对该类及其函数的作用和大致实现方式的介绍:

  • DataWriterImpl(PublisherImpl*, TypeSupport, Topic*, const DataWriterQos&, DataWriterListener*):类的构造函数,用于创建DataWriterImpl对象并初始化其成员变量。
  • ~DataWriterImpl():类的析构函数,用于清理资源和释放内存。
  • enable():启用DataWriterImpl对象,创建底层实体(RTPSWriter)等。
  • loan_sample(void*, LoanInitializationKind):从内部池中借用一个样本,用于写入数据。
  • discard_loan(void*&):废弃之前借用的样本。
  • write(void*):将数据写入到Topic中。
  • write(void*, fastrtps::rtps::WriteParams&):附带写入参数,将数据写入到Topic中。
  • write(void*, const InstanceHandle_t&):将数据写入到指定的实例中。
  • write_w_timestamp(void*, const InstanceHandle_t&, const fastrtps::Time_t&):附带时间戳,将数据写入到指定的实例中。
  • register_instance(void*):注册一个新的实例,并返回实例的句柄。
  • register_instance_w_timestamp(void*, const fastrtps::Time_t&):附带时间戳,注册一个新的实例,并返回实例的句柄。
  • unregister_instance(void*, const InstanceHandle_t&, bool = false):注销指定实例。
  • unregister_instance_w_timestamp(void*, const InstanceHandle_t&, const fastrtps::Time_t&, bool = false):附带时间戳,注销指定实例。
  • guid():获取DataWriter的GUID。
  • get_instance_handle():获取DataWriter的实例句柄。
  • get_type():获取数据类型支持对象。
  • get_qos():获取DataWriter的QoS配置。
  • get_topic():获取DataWriter关联的Topic。
  • get_listener():获取DataWriter的监听器。
  • set_listener(DataWriterListener*):设置DataWriter的监听器。
  • get_publication_matched_status(PublicationMatchedStatus&):获取发布匹配状态。
  • get_offered_deadline_missed_status(OfferedDeadlineMissedStatus&):获取未满足的最后期限状态。
  • get_offered_incompatible_qos_status(OfferedIncompatibleQosStatus&):获取不兼容的QoS状态。
  • set_qos(const DataWriterQos&):设置DataWriter的QoS配置。
  • get_liveliness_lost_status(LivelinessLostStatus&):获取失去活跃性的状态。
  • get_publisher():获取关联的Publisher。
  • assert_liveliness():声明活跃性。
  • disable():禁用DataWriterImpl对象,移除所有监听器。
  • clear_history(size_t*):清除历史记录中的所有数据。
  • get_sending_locators(rtps::LocatorList&):获取DataWriter可以发送数据的定位器列表。
  • filter_is_being_removed(const char*):在过滤器被移除时调用的方法。
关键函数分析

write

ReturnCode_t DataWriterImpl::write(void* data)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    // 检查数据是否为空
    if (data == nullptr)
    {
        return ReturnCode_t::RETCODE_BAD_PARAMETER;
    }

    // 检查数据共享是否兼容
    if (is_data_sharing_compatible_)
    {
        // 使用负载池分配Payload
        SerializedPayload_t payload;
        if (!get_payload_pool()->get_payload(payload))
        {
            return ReturnCode_t::RETCODE_OUT_OF_RESOURCES;
        }

        // 序列化数据到负载中
        if (!type_->serialize(data, &payload))
        {
            get_payload_pool()->release_payload(payload);
            return ReturnCode_t::RETCODE_ERROR;
        }

        // 创建新的更改并添加到历史记录中
        WriteParams wparams;
        ReturnCode_t ret = create_new_change_with_params(ALIVE, data, wparams);
        if (ret != ReturnCode_t::RETCODE_OK)
        {
            get_payload_pool()->release_payload(payload);
            return ret;
        }

        // 设置负载并发布更改
        CacheChange_t* change = history_.get_last_added_change();
        change->serializedPayload = payload;
        writer_->add_change(change);
    }
    else
    {
        // 使用内部负载分配器分配Payload
        std::unique_ptr<SerializedPayload_t> payload(new SerializedPayload_t());
        if (!payload || !get_payload_pool()->get_payload(*payload))
        {
            return ReturnCode_t::RETCODE_OUT_OF_RESOURCES;
        }

        // 序列化数据到负载中
        if (!type_->serialize(data, payload.get()))
        {
            get_payload_pool()->release_payload(*payload);
            return ReturnCode_t::RETCODE_ERROR;
        }

        // 创建新的更改并添加到历史记录中
        WriteParams wparams;
        ReturnCode_t ret = create_new_change_with_params(ALIVE, data, wparams);
        if (ret != ReturnCode_t::RETCODE_OK)
        {
            get_payload_pool()->release_payload(*payload);
            return ret;
        }

        // 设置负载并发布更改
        CacheChange_t* change = history_.get_last_added_change();
        change->serializedPayload = *payload;
        writer_->add_change(change);
    }

    return ReturnCode_t::RETCODE_OK;
}

write函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 然后,检查数据是否为空,如果为空则返回RETCODE_BAD_PARAMETER。
  3. 接下来,根据数据共享的兼容性情况,选择使用不同的负载分配器。
  4. 如果数据共享兼容,则使用负载池分配SerializedPayload_t对象,然后将数据序列化到负载中。
  5. 创建新的更改并将其添加到历史记录中。
  6. 设置负载并将更改添加到DataWriter中。
  7. 如果数据共享不兼容,则使用内部负载分配器分配SerializedPayload_t对象,然后将数据序列化到负载中。
  8. 创建新的更改并将其添加到历史记录中。
  9. 设置负载并将更改添加到DataWriter中。
  10. 返回RETCODE_OK表示写入操作成功。

write_w_timestamp

ReturnCode_t DataWriterImpl::write_w_timestamp(void* data, const fastrtps::Time_t& timestamp)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    // 检查数据是否为空
    if (data == nullptr)
    {
        return ReturnCode_t::RETCODE_BAD_PARAMETER;
    }

    // 检查数据共享是否兼容
    if (is_data_sharing_compatible_)
    {
        // 使用负载池分配Payload
        SerializedPayload_t payload;
        if (!get_payload_pool()->get_payload(payload))
        {
            return ReturnCode_t::RETCODE_OUT_OF_RESOURCES;
        }

        // 序列化数据到负载中
        if (!type_->serialize(data, &payload))
        {
            get_payload_pool()->release_payload(payload);
            return ReturnCode_t::RETCODE_ERROR;
        }

        // 创建新的更改并添加到历史记录中
        WriteParams wparams;
        ReturnCode_t ret = create_new_change_with_params(ALIVE, data, wparams);
        if (ret != ReturnCode_t::RETCODE_OK)
        {
            get_payload_pool()->release_payload(payload);
            return ret;
        }

        // 设置时间戳并发布更改
        CacheChange_t* change = history_.get_last_added_change();
        change->serializedPayload = payload;
        change->sourceTimestamp = timestamp;
        writer_->add_change(change);
    }
    else
    {
        // 使用内部负载分配器分配Payload
        std::unique_ptr<SerializedPayload_t> payload(new SerializedPayload_t());
        if (!payload || !get_payload_pool()->get_payload(*payload))
        {
            return ReturnCode_t::RETCODE_OUT_OF_RESOURCES;
        }

        // 序列化数据到负载中
        if (!type_->serialize(data, payload.get()))
        {
            get_payload_pool()->release_payload(*payload);
            return ReturnCode_t::RETCODE_ERROR;
        }

        // 创建新的更改并添加到历史记录中
        WriteParams wparams;
        ReturnCode_t ret = create_new_change_with_params(ALIVE, data, wparams);
        if (ret != ReturnCode_t::RETCODE_OK)
        {
            get_payload_pool()->release_payload(*payload);
            return ret;
        }

        // 设置时间戳并发布更改
        CacheChange_t* change = history_.get_last_added_change();
        change->serializedPayload = *payload;
        change->sourceTimestamp = timestamp;
        writer_->add_change(change);
    }

    return ReturnCode_t::RETCODE_OK;
}

write_w_timestamp函数与write函数的实现非常相似。不同之处在于它接受一个额外的参数timestamp,用于指定数据的时间戳。

write_w_timestamp函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 然后,检查数据是否为空,如果为空则返回RETCODE_BAD_PARAMETER。
  3. 接下来,根据数据共享的兼容性情况,选择使用不同的负载分配器。
  4. 如果数据共享兼容,则使用负载池分配SerializedPayload_t对象,并将数据序列化到负载中。
  5. 创建新的更改并将其添加到历史记录中。
  6. 设置时间戳并将更改添加到DataWriter中。
  7. 如果数据共享不兼容,则使用内部负载分配器分配SerializedPayload_t对象,并将数据序列化到负载中。
  8. 创建新的更改并将其添加到历史记录中。
  9. 设置时间戳并将更改添加到DataWriter中。
  10. 返回RETCODE_OK表示写入操作成功。


 

register_instance

ReturnCode_t DataWriterImpl::register_instance(void* key)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    // 检查键值是否为空
    if (key == nullptr)
    {
        return ReturnCode_t::RETCODE_BAD_PARAMETER;
    }

    // 检查键是否已注册
    if (history_.key_exists(key))
    {
        return ReturnCode_t::RETCODE_PRECONDITION_NOT_MET;
    }

    // 创建新的更改并添加到历史记录中
    WriteParams wparams;
    ReturnCode_t ret = create_new_change_with_params(NOT_ALIVE_UNREGISTERED, key, wparams);
    if (ret != ReturnCode_t::RETCODE_OK)
    {
        return ret;
    }

    // 将实例注册到历史记录中
    CacheChange_t* change = history_.get_last_added_change();
    history_.register_instance(change, key);

    return ReturnCode_t::RETCODE_OK;
}

register_instance函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 然后,检查键值是否为空,如果为空则返回RETCODE_BAD_PARAMETER。
  3. 接下来,检查键是否已经注册,如果已经注册则返回RETCODE_PRECONDITION_NOT_MET。
  4. 创建新的更改并将其添加到历史记录中。这里使用create_new_change_with_params函数创建一个新的更改,更改类型为NOT_ALIVE_UNREGISTERED,数据为键值。
  5. 将实例注册到历史记录中。通过调用register_instance函数将更改与键值关联起来,这样历史记录就可以跟踪实例的状态。
  6. 返回RETCODE_OK表示注册实例操作成功。

history_是DataWriterImpl类中的成员变量,它是用来管理DataWriter的历史更改记录的对象。

history_的作用是存储DataWriter发送的所有更改。每当DataWriter要发送新的数据时,它会创建一个新的更改(CacheChange_t对象),并将其添加到history_中。历史记录中的更改可以按照序列号进行排序,以便按照正确的顺序发送和传输数据。

通过管理历史记录,DataWriter可以实现一些重要的功能,例如支持可靠性、历史访问、数据回溯和重传等。历史记录还可用于处理订阅者的需求,如按需读取、历史数据查询和数据过滤等。

在DataWriterImpl中,history_是一个WriterHistory类型的对象,它实现了管理和维护历史更改记录的功能。WriterHistory是Fast DDS库提供的一个用于管理历史更改的实现。

通过使用history_,DataWriter可以跟踪和管理发送的数据,保证数据可靠性和一致性,并提供灵活的历史访问和数据处理能力。

get_publication_matched_status

ReturnCode_t DataWriterImpl::get_publication_matched_status(PublicationMatchedStatus& status)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    {
        std::unique_lock<RecursiveTimedMutex> lock(writer_->getMutex());

        // 获取PublicationMatchedStatus并复制给status参数
        status = publication_matched_status_;

        // 重置current_count_change和total_count_change
        publication_matched_status_.current_count_change = 0;
        publication_matched_status_.total_count_change = 0;
    }

    // 设置相应的状态条件
    user_datawriter_->get_statuscondition().get_impl()->set_status(StatusMask::publication_matched(), false);

    return ReturnCode_t::RETCODE_OK;
}

get_publication_matched_status函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 使用std::unique_lock对DataWriter的互斥锁进行加锁,以确保线程安全性。
  3. 将publication_matched_status_复制到status参数中。
  4. 重置publication_matched_status_中的current_count_change和total_count_change为0,以表示已经处理了这些变化。
  5. 通过调用user_datawriter_->get_statuscondition().get_impl()->set_status()设置相应的状态条件,将publication_matched_status_的变化通知给用户。
  6. 返回RETCODE_OK表示获取PublicationMatchedStatus成功。

DataWriter的当前PublicationMatchedStatus表示与该DataWriter相关的订阅者(DataReader)的匹配状态。PublicationMatchedStatus记录了与DataWriter相关的订阅者数量的变化情况。

PublicationMatchedStatus结构包含以下字段:

  • total_count: 表示与DataWriter相关的总订阅者数量。
  • total_count_change: 表示自上次获取PublicationMatchedStatus以来总订阅者数量的变化值。
  • current_count: 表示当前与DataWriter匹配的订阅者数量。
  • current_count_change: 表示自上次获取PublicationMatchedStatus以来当前订阅者数量的变化值。

通过监视PublicationMatchedStatus的变化,可以了解DataWriter与订阅者之间的匹配情况的变化。例如,当新的订阅者与DataWriter匹配时,current_count和total_count会增加,并且可以通过检查current_count_change和total_count_change字段来获知匹配状态的变化。

使用PublicationMatchedStatus可以实现一些功能,例如:

  • 监测DataWriter与订阅者的连接状态,以便确定是否成功建立了通信连接。
  • 根据与DataWriter匹配的订阅者数量来调整数据发布的策略。
  • 基于PublicationMatchedStatus的变化触发特定的操作或回调函数

get_offered_deadline_missed_status

ReturnCode_t DataWriterImpl::get_offered_deadline_missed_status(OfferedDeadlineMissedStatus& status)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    {
        std::unique_lock<RecursiveTimedMutex> lock(writer_->getMutex());

        // 获取OfferedDeadlineMissedStatus并复制给status参数
        status = offered_deadline_missed_status_;

        // 重置total_count和total_count_change
        offered_deadline_missed_status_.total_count_change = 0;
    }

    // 设置相应的状态条件
    user_datawriter_->get_statuscondition().get_impl()->set_status(StatusMask::offered_deadline_missed(), false);

    return ReturnCode_t::RETCODE_OK;
}

get_offered_deadline_missed_status函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 使用std::unique_lock对DataWriter的互斥锁进行加锁,以确保线程安全性。
  3. 将offered_deadline_missed_status_复制到status参数中。
  4. 重置offered_deadline_missed_status_中的total_count_change为0,以表示已经处理了这些变化。
  5. 通过调用user_datawriter_->get_statuscondition().get_impl()->set_status()设置相应的状态条件,将OfferedDeadlineMissedStatus的变化通知给用户。
  6. 返回RETCODE_OK表示获取OfferedDeadlineMissedStatus成功。

OfferedDeadlineMissedStatus表示DataWriter的最后期限未达到的情况。该状态记录了DataWriter未能按照其所定义的最后期限要求及时发送数据的统计信息。

OfferedDeadlineMissedStatus结构包含以下字段:

  • total_count:表示自DataWriter启动以来,达到或超过最后期限的次数总计。
  • total_count_change:表示自上次获取OfferedDeadlineMissedStatus以来,达到或超过最后期限的次数的变化值。

通过监视OfferedDeadlineMissedStatus的变化,可以了解DataWriter未按照最后期限要求发送数据的情况。当DataWriter未能及时发送数据时,total_count和total_count_change字段将增加,可以通过检查这些字段的值来获知最后期限未达到的次数和变化情况。

使用OfferedDeadlineMissedStatus可以实现一些功能,例如:

  • 监测DataWriter是否按照最后期限要求及时发送数据。
  • 根据最后期限未达到的情况采取相应的容错措施,例如重新发送数据或进行补偿操作。
  • 基于OfferedDeadlineMissedStatus的变化触发特定的操作或回调函数。


get_offered_incompatible_qos_status

ReturnCode_t DataWriterImpl::get_offered_incompatible_qos_status(OfferedIncompatibleQosStatus& status)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    {
        std::unique_lock<RecursiveTimedMutex> lock(writer_->getMutex());

        // 获取OfferedIncompatibleQosStatus并复制给status参数
        status = offered_incompatible_qos_status_;

        // 重置total_count和total_count_change
        offered_incompatible_qos_status_.total_count_change = 0;
    }

    // 设置相应的状态条件
    user_datawriter_->get_statuscondition().get_impl()->set_status(StatusMask::offered_incompatible_qos(), false);

    return ReturnCode_t::RETCODE_OK;
}

get_offered_incompatible_qos_status函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 使用std::unique_lock对DataWriter的互斥锁进行加锁,以确保线程安全性。
  3. 将offered_incompatible_qos_status_复制到status参数中。
  4. 重置offered_incompatible_qos_status_中的total_count_change为0,以表示已经处理了这些变化。
  5. 通过调用user_datawriter_->get_statuscondition().get_impl()->set_status()设置相应的状态条件,将OfferedIncompatibleQosStatus的变化通知给用户。
  6. 返回RETCODE_OK表示获取OfferedIncompatibleQosStatus成功。

OfferedIncompatibleQosStatus表示DataWriter提供的QoS(Quality of Service)与订阅者(DataReader)的QoS不兼容的情况。该状态记录了DataWriter与订阅者之间QoS不兼容的统计信息。

OfferedIncompatibleQosStatus结构包含以下字段:

  • total_count:表示自DataWriter启动以来,发现的不兼容QoS的次数总计。
  • total_count_change:表示自上次获取OfferedIncompatibleQosStatus以来,发现的不兼容QoS的次数的变化值。

通过监视OfferedIncompatibleQosStatus的变化,可以了解DataWriter与订阅者之间QoS不兼容的情况。当DataWriter与订阅者发现不兼容的QoS时,total_count和total_count_change字段将增加,可以通过检查这些字段的值来获知不兼容QoS的次数和变化情况。

使用OfferedIncompatibleQosStatus可以实现一些功能,例如:

  • 监测DataWriter与订阅者之间QoS的兼容性情况。
  • 根据不兼容QoS的情况进行相应的处理,例如尝试重新配置QoS或与订阅者进行协商。
  • 基于OfferedIncompatibleQosStatus的变化触发特定的操作或回调函数。

get_liveliness_lost_status

ReturnCode_t DataWriterImpl::get_liveliness_lost_status(LivelinessLostStatus& status)
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    {
        std::unique_lock<RecursiveTimedMutex> lock(writer_->getMutex());

        // 获取LivelinessLostStatus并复制给status参数
        status = liveliness_lost_status_;

        // 重置total_count和total_count_change
        liveliness_lost_status_.total_count_change = 0;
    }

    // 设置相应的状态条件
    user_datawriter_->get_statuscondition().get_impl()->set_status(StatusMask::liveliness_lost(), false);

    return ReturnCode_t::RETCODE_OK;
}

get_liveliness_lost_status函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 使用std::unique_lock对DataWriter的互斥锁进行加锁,以确保线程安全性。
  3. 将liveliness_lost_status_复制到status参数中。
  4. 重置liveliness_lost_status_中的total_count_change为0,以表示已经处理了这些变化。
  5. 通过调用user_datawriter_->get_statuscondition().get_impl()->set_status()设置相应的状态条件,将LivelinessLostStatus的变化通知给用户。
  6. 返回RETCODE_OK表示获取LivelinessLostStatus成功。

在数据通信中,活跃性(Liveliness)是指一个实体(如DataWriter)继续存在和活跃的状态。在发布-订阅模型中,DataWriter通过发送活跃性消息或定期发送心跳消息来证明自己的活跃状态。这样,订阅者(DataReader)能够确认DataWriter是否仍然处于活跃状态,以便维持通信链接。

活跃性的目的是确保数据通信中的实体保持活跃,以便保持通信链路的有效性和一致性。通过活跃性机制,可以检测到DataWriter是否不再活跃,即停止发送活跃性消息或心跳消息,或者由于某些原因无法满足活跃性要求。当DataWriter丢失活跃性时,订阅者可以做出相应的处理,如更新订阅者的状态、重新分配资源或采取其他容错措施。

get_sending_locators

ReturnCode_t DataWriterImpl::get_sending_locators(rtps::LocatorList& locators) const
{
    // 检查DataWriter是否已启用
    if (writer_ == nullptr)
    {
        return ReturnCode_t::RETCODE_NOT_ENABLED;
    }

    // 获取DataWriter正在使用的发送定位器列表
    rtps::LocatorList sending_locators = writer_->getRTPSParticipant()->getSendingLocators();

    // 将发送定位器列表复制给输出参数locators
    locators = sending_locators;

    return ReturnCode_t::RETCODE_OK;
}

get_sending_locators函数的主要步骤如下:

  1. 首先,检查DataWriter是否已启用,如果未启用则返回RETCODE_NOT_ENABLED。
  2. 调用writer_->getRTPSParticipant()->getSendingLocators()获取DataWriter正在使用的发送定位器列表。
  3. 将发送定位器列表复制给输出参数locators。
  4. 返回RETCODE_OK表示获取发送定位器列表成功。

通过调用get_sending_locators函数,可以获取DataWriter正在使用的发送定位器列表。发送定位器列表包含了DataWriter用于发送数据的网络定位器信息,可用于了解DataWriter当前的通信配置和连接信息。这对于监视和调试数据传输以及网络配置非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/751367.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git #01 操作记录

本篇内容 0. 前期配置1. 仓库1.1 上传本地代码到远程仓库 0. 前期配置 请提前配置好 git 的全局用户名&#xff1a; # xin&#xff1a;账号名 $ git config --global user.name "xin" # xin163.com&#xff1a;账号绑定的邮箱地址 $ git config --global user.emai…

单片机能否替代PLC实现控制和自动化系统?

是的&#xff0c;单片机可以在某些情况下替代PLC&#xff0c;但在其他情况下可能并不适用。以下是对这个问题的详细解释&#xff1a; 我这里刚好有嵌入式、单片机、plc的资料需要可以私我或在评论区扣个6 灵活性和可编程性&#xff1a;PLC相对于单片机来说更具有灵活性和可编…

DolphinScheduler minio(S3支持)开启资源中心

DolphinScheduler 如果是在3.0.5 及之前的版本&#xff0c;没办法支持 S3 的协议的 当你按照文档配置之后&#xff0c;运行启动之后&#xff0c;在master 和 worker 节点&#xff0c;都会出现 缺包的依赖问题。 那这个问题在什么版本修复了呢&#xff1f; 3.0.6... 那 3.0.6 …

每个前端开发者都应知道的10个实用网站

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的&#xff0c;我们出的钱 体验地…

sprinboot企业客户信息反馈平台

企业客户信息反馈平台的开发运用java技术&#xff0c;MIS的总体思想&#xff0c;以及MYSQL等技术的支持下共同完成了该平台的开发&#xff0c;实现了企业客户信息反馈管理的信息化&#xff0c;使用户体验到更优秀的企业客户信息反馈管理&#xff0c;管理员管理操作将更加方便&a…

canal番外篇-otter

前置知识点 主从复制binlogcanal正则dockerjava 前置工具 dockerotter-all 场景描述&#xff08;增量同步&#xff09; 目前项目中使用的是mysql5.5&#xff0c;计划升级为mysql8.1&#xff0c;版本跨度较大&#xff0c;市面上可靠工具选择较少。otter符合预期&#xff0c…

3Ds max入门教程:为男性角色创建服装T 恤

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 3ds Max 角色服装教程 在本 3ds Max 教程中&#xff0c;我们将为角色模型创建一个简单的 T 恤。我们提供了一个“human_figure.obj”文件供您导入模型。因此&#xff0c;本教程将重点介绍的是创建服装&…

【VTK】VTK 显示小球例子,在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 关于更多此例子的资料&#xff0c;可以参考&#xff1a;【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。 文章目录 版本环境VTKTest.…

【机器人模拟-01】使用URDF在中创建模拟移动机器人

一、说明 在本教程中,我将向您展示如何使用通用机器人描述格式 (URDF)(机器人建模的标准 ROS 格式)创建模拟移动机器人。 机器人专家喜欢在构建机器人之前对其进行模拟,以测试不同的算法。您可以想象,使用物理机器人犯错的成本可能很高(例如,将移动机器人高速…

SPSS方差分析

参考文章 导入准备好的数据 选择分析方法 选择参数 选择对比&#xff0c;把组别放入因子框中&#xff0c;把红细胞增加数放进因变量列表 勾选“多项式”&#xff0c;等级取默认“线性” &#xff0c;继续 接着点击“事后比较”&#xff0c;弹出对话框&#xff0c;勾选“LSD” …

华为OD机试真题 JavaScript 实现【分糖果】【2022Q2 200分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、JavaScript算法源码六、效果展示 专栏导读 本专栏收录于《华为OD机试&#xff08;JavaScript&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都…

Windows Bat实现延时功能的几种常见方式

文章目录 1. 使用ping命令实现延时2. 使用timeout命令实现延时3. 使用choice命令实现延时4. 使用for循环实现延时5. 使用sleep命令实现延时6. 使用VBScript.sleep实现延时总结 在 bat批处理中实现延时功能的几种常用方式 1. 使用ping命令实现延时 使用ping命令可以实现延时的…

mysql备份,视图

一、备份与还原 1.设计样例表 CREATE DATABASE booksDB; use booksDB; --创建表book2 CREATE TABLE books(bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL); --创建表authors CREATE TABLE authors(auth_id INT NOT NULL PRIM…

java学习路程之篇六、知识点、算数运算符、自增自减运算符、类型转换

文章目录 1、算术运算符2、自增自减运算符3、类型转换 1、算术运算符 2、自增自减运算符 3、类型转换

Serverless是什么?如何使用?有哪些优势?国内外有哪些Serverless平台?

111. Serverless是什么&#xff1f;如何使用&#xff1f;有哪些优势&#xff1f;国内外有哪些Serverless平台&#xff1f; 一、 Serverless是什么&#xff1f; 百度百科 Serverless 是云计算的一种模型。以平台即服务&#xff08;PaaS&#xff09;为基础&#xff0c;无服务器…

【沐风老师】3DMAX灯光放置插件LightPlacer使用方法教程

3DMAX灯光放置插件LightPlacer使用方法 3DMAX灯光放置插件LightPlacer&#xff0c;用于3dMax放置和管理灯光的插件&#xff0c;可以在3dMax中一键制作所需的灯光&#xff0c;且通过插件创建出来的灯光属性可以在该面板下进行直接修改&#xff0c;并不需要切换至堆栈。该插件的有…

接口自动化测试实践指导(下):接口自动化测试断言设置思路

1 断言设置思路 这里总结了我在项目中常用的5种断言方式&#xff0c;基本可能满足90%以上的断言场景&#xff0c;具体参见如下脑图&#xff1a; 下面分别解释一下图中的五种思路&#xff1a; 1&#xff09; 响应码 对于http类接口&#xff0c;有时开发人员只是通过设置接口响…

IDEA的火焰图简单使用

1. 火焰图是什么&#xff1f; 简单来说就是用来查看程序耗时的一张图 如何读懂火焰图&#xff1f; 2. mac上如何生成火焰图 找了一圈&#xff0c;原来idea原本就支持… 3. 测试代码 package org.example;import java.util.ArrayList; import java.util.List; import java.…

QT Quick初学笔记---第一篇

1、对Qt Quick的初步认识 Qt Quick是Qt5界面开发技术的统称&#xff0c;是以下几种技术的集合&#xff1a; QML&#xff1a;界面标记语言JavaScript&#xff1a;动态脚本语言QT C&#xff1a;跨平台C封装库 QML是与HTML类似的一种标记语言。 QML文件采用.qml作为文件格式后…

C语言、C++和C#:区别与特点的比较

C语言、C和C#是三种不同的编程语言&#xff0c;它们在以下几个方面存在区别&#xff1a; 设计宗旨&#xff1a;C语言是一种过程式编程语言&#xff0c;旨在提供高效的系统级编程。C是在C语言基础上发展而来的&#xff0c;既支持过程式编程&#xff0c;也支持面向对象编程。C#是…