Fast-DDS 接收数据完整时序分析

Fast-DDS 接收数据完整时序分析

⚠️ 重要声明
本文档基于 Fast-DDS 特定 commit 版本分析,代码接口可能随版本演进发生变化。

  • Commit ID : 5d3acdcba3f57391ad08b2739b09e70f3a2492ea
  • Commit Date: 2026-02-26
  • Branch: master / origin/3.5.x
  • Author : Raül Ojeda Gandia raulojeda@eprosima.com

阅读建议: 如遇到接口不匹配,请检查当前代码版本与上述 commit 的差异。
文档说明: 本文档详细分析 Fast-DDS (eProsima Fast DDS v3.5.0) 从网络层接收到应用层获取数据的完整调用流程,包含三层架构、关键分支机制、以及 Listener 模式的数据获取原理。


📋 目录

  1. 总体架构概览
  2. 第一层:网络传输层
  3. [第二层:RTPS 协议解析层](#第二层:RTPS 协议解析层)
  4. [第三层:DDS 应用层](#第三层:DDS 应用层)
  5. [Listener 模式详解](#Listener 模式详解)
  6. 高性能优化机制
  7. 完整时序图
  8. 关键代码位置索引

1. 总体架构概览

Fast-DDS 的接收数据流程采用三层架构设计,每层职责清晰,通过模块化实现高可扩展性:

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Network Layer (网络层)                     │
│  ASIO Socket → UDP/TCP Transport → Channel Resource         │
└──────────────────────────┬──────────────────────────────────┘
                           │ 原始数据包
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                 RTPS Protocol Layer (协议层)                  │
│  MessageReceiver → 三处关键分支 → Stateful/StatelessReader  │
└──────────────────────────┬──────────────────────────────────┘
                           │ CacheChange_t
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  DDS Application Layer (应用层)               │
│  DataReaderImpl → History 管理 → Listener 回调 → 用户代码    │
└─────────────────────────────────────────────────────────────┘

核心设计理念

设计原则 说明
分层解耦 网络、协议、应用三层独立,便于扩展和维护
通知与获取分离 on_data_available() 仅通知,take() 主动获取数据
命令模式封装 ReadTakeCommand 统一处理复杂的 read/take 逻辑
高性能优化 栈上分配、零拷贝支持、线程安全锁机制

2. 第一层:网络传输层

2.1 数据接收流程

网络层负责从物理网络接收原始数据包,并通过 ASIO 异步 IO 传递给上层。

调用链路
复制代码
Network Packet
    ↓
ASIO Socket::recv_from()
    ↓
UDPChannelResource::perform_listen_operation()
    ↓
ReceiverResource::OnDataReceived(buffer, length, input_locator, remote_locator)
关键代码

文件位置 : src/cpp/rtps/transport/UDPChannelResource.cpp:61-87

cpp 复制代码
// UDPChannelResource::perform_listen_operation()
void UDPChannelResource::perform_listen_operation(Locator input_locator)
{
    Locator remote_locator;

    // 在独立线程中循环接收数据
    while (alive())
    {
        // 同步阻塞接收(Blocking receive)
        auto& msg = message_buffer();
        if (!Receive(msg.buffer, msg.max_size, msg.length, remote_locator))
        {
            continue;  // 接收失败,继续下一次循环
        }

        // 通过 CDR Message 接口处理数据
        if (message_receiver() != nullptr)
        {
            // 调用 ReceiverResource 处理
            message_receiver()->OnDataReceived(
                msg.buffer, 
                msg.length, 
                input_locator,      // 本地监听地址
                remote_locator);    // 远程发送者地址
        }
        else if (alive())
        {
            EPROSIMA_LOG_WARNING(RTPS_MSG_IN, "Received Message, but no receiver attached");
        }
    }

    message_receiver(nullptr);
}

// UDPChannelResource::Receive() - 底层同步接收实现
bool UDPChannelResource::Receive(
    octet* receive_buffer,
    uint32_t receive_buffer_capacity,
    uint32_t& receive_buffer_size,
    Locator& remote_locator)
{
    try
    {
        asio::ip::udp::endpoint senderEndpoint;
        
        // 同步阻塞调用 ASIO 的 receive_from
        size_t bytes = socket()->receive_from(
            asio::buffer(receive_buffer, receive_buffer_capacity), 
            senderEndpoint);
        
        receive_buffer_size = static_cast<uint32_t>(bytes);
        
        if (receive_buffer_size > 0)
        {
            // 将 ASIO endpoint 转换为 Fast-DDS Locator
            transport_->endpoint_to_locator(senderEndpoint, remote_locator);
        }
        
        return (receive_buffer_size > 0);
    }
    catch (const std::exception& error)
    {
        EPROSIMA_LOG_WARNING(RTPS_MSG_OUT, "Error receiving data: " << error.what());
        return false;
    }
}

关键点:

  • ✅ 使用独立线程 运行 perform_listen_operation()
  • ✅ 采用同步阻塞 方式调用 socket()->receive_from()
  • ✅ 通过 while(alive()) 循环持续接收数据
  • ✅ 接收成功后调用 OnDataReceived() 传递给 RTPS 层

3. 第二层:RTPS 协议解析层

RTPS 层是 Fast-DDS 的核心,负责解析 DDS 标准定义的 RTPS 协议消息。该层包含三处关键分支,决定了数据的处理路径。

3.1 入口函数:MessageReceiver::processCDRMsg()

文件位置 : src/cpp/rtps/messages/MessageReceiver.cpp:250-500

cpp 复制代码
bool MessageReceiver::processCDRMsg(
    const Locator_t& source_locator,
    const Locator_t& remote_locator,
    const octet* buffer,
    size_t buffer_size)
{
    // 1. 解析 RTPS 头部
    CDRMessage_t msg;
    msg.init(buffer, buffer_size);
    
    RTPSMessageHeader_t header;
    if (!CDRMessage::readRTPSMessageHeader(&msg, &header))
    {
        return false;
    }
    
    // 2. 循环解析子消息
    while (msg.pos < msg.length)
    {
        SubmessageHeader_t submsg_header;
        CDRMessage::readSubmessageHeader(&msg, &submsg_header);
        
        // 【分支1】根据子消息类型分发
        switch (submsg_header.submessageId)
        {
            case DATA:
                proc_Submsg_Data(&msg, &submsg_header, ...);
                break;
            case DATA_FRAG:
                proc_Submsg_DataFrag(&msg, &submsg_header, ...);
                break;
            case HEARTBEAT:
                proc_Submsg_Heartbeat(&msg, &submsg_header, ...);
                break;
            case ACKNACK:
                proc_Submsg_Acknack(&msg, &submsg_header, ...);
                break;
            case GAP:
                proc_Submsg_Gap(&msg, &submsg_header, ...);
                break;
            // ... 其他子消息类型
        }
    }
    
    return true;
}

3.2 【分支1】子消息类型分发

决策依据: RTPS 协议定义的子消息 ID

子消息类型 处理函数 作用
DATA proc_Submsg_Data() 处理完整数据样本
DATA_FRAG proc_Submsg_DataFrag() 处理分片数据
HEARTBEAT proc_Submsg_Heartbeat() 可靠性心跳(RELIABLE 模式)
ACKNACK proc_Submsg_Acknack() 确认/否定确认(RELIABLE 模式)
GAP proc_Submsg_Gap() 序列号间隙通知
INFO_SRC proc_Submsg_InfoSRC() 源信息(GUID、版本等)
INFO_TS proc_Submsg_InfoTS() 时间戳信息

设计目的: 支持 RTPS 协议的多种消息类型,实现完整的发布-订阅语义。


3.3 【分支2】安全/非安全路径选择

DATA 子消息为例,展示第二处分支:

文件位置 : src/cpp/rtps/messages/MessageReceiver.cpp:68-105

复制代码
// MessageReceiver 构造函数中初始化函数指针
MessageReceiver::MessageReceiver(RTPSParticipantImpl* participant)
{
#ifdef HAVE_SECURITY
    // 启用 DDS Security 标准
    process_data_message_function_ = 
        &MessageReceiver::process_data_message_with_security;
#else
    // 非安全模式(默认)
    process_data_message_function_ = 
        &MessageReceiver::process_data_message_without_security;
#endif
}

// proc_Submsg_Data() 解析完 DATA 内容后调用
void MessageReceiver::proc_Submsg_Data(...)
{
    // 1. 解析 ReaderID、WriterGUID、SequenceNumber
    // 2. 解析 InlineQoS
    // 3. 提取 Payload
    
    CacheChange_t change;
    change.writerGUID = writer_guid;
    change.sequenceNumber = seq_num;
    // ... 填充其他字段
    
    // 【分支2】通过函数指针调用
    bool was_decoded = false;
    process_data_message_function_(reader_id, &change, was_decoded);
}
两条处理路径

路径 A: 非安全模式(默认)

文件位置 : src/cpp/rtps/messages/MessageReceiver.cpp:221-232

cpp 复制代码
void MessageReceiver::process_data_message_without_security(
    const EntityId_t& reader_id,
    CacheChange_t* change,
    bool& was_decoded)
{
    // 直接查找匹配的 Reader
    findAllReaders(reader_id, [change, &was_decoded](BaseReader* reader)
    {
        was_decoded = true;
        // 调用 Reader 的处理方法
        reader->process_data_msg(change);
    });
}

路径 B: 安全模式(启用加密)

文件位置 : src/cpp/rtps/messages/MessageReceiver.cpp:127-167

复制代码
void MessageReceiver::process_data_message_with_security(
    const EntityId_t& reader_id,
    CacheChange_t* change,
    bool& was_decoded)
{
    // 1. 解密 payload
    SecurityManager* security_manager = participant_->security_manager();
    if (!security_manager->decode_serialized_payload(
            change->serializedPayload, 
            decoded_payload,
            change->writerGUID))
    {
        return; // 解密失败
    }
    
    // 2. 替换为解密后的 payload
    change->serializedPayload = decoded_payload;
    was_decoded = true;
    
    // 3. 查找匹配的 Reader
    findAllReaders(reader_id, [change, &was_decoded](BaseReader* reader)
    {
        reader->process_data_msg(change);
    });
}

设计目的:

  • ✅ 支持可选的 DDS Security 标准
  • ✅ 透明加解密,对上层应用无感知
  • ✅ 函数指针分发,避免运行时条件判断开销

3.4 【分支3】Reader 类型多态

文件位置 : src/cpp/rtps/reader/StatefulReader.cpp:567

复制代码
// BaseReader 定义纯虚函数
class BaseReader
{
public:
    virtual bool process_data_msg(CacheChange_t* change) = 0;
};

// StatefulReader 实现(RELIABLE 模式)
bool StatefulReader::process_data_msg(CacheChange_t* change)
{
    // 1. 查找或创建 WriterProxy
    WriterProxy* pWP = nullptr;
    if (!acceptMsgFrom(change->writerGUID, &pWP))
    {
        return false;
    }
    
    // 2. 检查是否已接收过该序列号
    if (pWP->change_was_received(change->sequenceNumber))
    {
        return false; // 重复数据,忽略
    }
    
    // 3. 检查 History 是否能接收
    if (!history_->can_change_be_added_nts(...))
    {
        return false;
    }
    
    // 4. 检查内容过滤
    if (!change_is_relevant_for_filter(change))
    {
        return false;
    }
    
    // 5. 从 pool 获取 CacheChange
    CacheChange_t* change_to_add = nullptr;
    if (!change_pool_->reserve_cache(&change_to_add))
    {
        return false;
    }
    
    // 6. 拷贝元数据
    change_to_add->copy_not_memcpy(change);
    
    // 7. 获取 payload
    if (!payload_pool_->get_payload(...))
    {
        change_pool_->release_cache(change_to_add);
        return false;
    }
    
    // 8. 添加到 History 并通知
    change_received(change_to_add, pWP, unknown_missing_changes_up_to);
    
    return true;
}

// StatelessReader 实现(BEST_EFFORT 模式)
bool StatelessReader::process_data_msg(CacheChange_t* change)
{
    // 简化流程:不维护 WriterProxy 状态
    // 直接添加到 History
    history_->add_change(change);
    listener_->onNewCacheChangeAdded(this, change);
    
    return true;
}
两种 Reader 对比
特性 StatefulReader StatelessReader
QoS 策略 RELIABLE(可靠) BEST_EFFORT(尽力而为)
状态管理 维护 WriterProxy,跟踪序列号 无状态
重传支持 ✅ 支持(通过 HEARTBEAT/ACKNACK) ❌ 不支持
性能 较低(需维护状态) 较高(无状态开销)
适用场景 关键数据传输 高频传感器数据

设计目的:

  • ✅ 通过虚函数多态支持不同的可靠性策略
  • ✅ 应用层无需关心底层实现细节
  • ✅ 符合开闭原则,易于扩展新的 Reader 类型

4. 第三层:DDS 应用层

DDS 层负责将 RTPS 层的原始数据转换为应用层可用的对象,并提供丰富的 QoS 策略和监听机制。

4.1 添加到 History

文件位置 : src/cpp/rtps/reader/StatefulReader.cpp:1085-1230

cpp 复制代码
bool StatefulReader::change_received(
    CacheChange_t* a_change,
    WriterProxy* pWP,
    size_t unknown_missing_changes_up_to)
{
    // 1. 更新 WriterProxy 状态
    pWP->received_change_set(a_change->sequenceNumber);
    
    // 2. 添加到 History
    if (!history_->received_change(a_change, unknown_missing_changes_up_to))
    {
        change_pool_->release_cache(a_change);
        return false;
    }
    
    // 3. 通知 Listener
    NotifyChanges(pWP);
    
    return true;
}

ReaderHistory::received_change() 内部逻辑:

cpp 复制代码
bool ReaderHistory::received_change(CacheChange_t* a_change, ...)
{
    // 1. 查找或创建 Instance
    InstanceHandle_t instance_handle = find_or_create_instance(a_change);
    
    // 2. 根据 History QoS 策略决定如何处理
    switch (qos_.history().kind)
    {
        case KEEP_LAST_HISTORY_QOS:
            // 保留最近 N 个样本(N = depth)
            if (instance->get_change_count() >= qos_.history().depth)
            {
                remove_oldest_change(instance);
            }
            break;
            
        case KEEP_ALL_HISTORY_QOS:
            // 保留所有样本(受资源限制)
            break;
    }
    
    // 3. 添加样本到实例
    instance->add_change(a_change);
    
    return true;
}

4.2 RTPS 层 → DDS 层桥接

文件位置 : src/cpp/rtps/reader/StatefulReader.cpp:1236-1300

复制代码
void StatefulReader::NotifyChanges(WriterProxy* prox)
{
    auto listener = get_listener();
    if (nullptr != listener)
    {
        bool notify_individual = false;
        
        // 计算序列号范围
        SequenceNumber_t first_seq = ...;
        SequenceNumber_t max_seq = ...;
        
        // 调用 RTPS ReaderListener
        listener->on_data_available(
            this, 
            prox->guid(), 
            first_seq, 
            max_seq, 
            notify_individual);
        
        // 如果需要逐个通知
        if (notify_individual)
        {
            auto it = history_->changesBegin();
            SequenceNumber_t next_seq = first_seq;
            
            while (next_seq <= max_seq && 
                   history_->changesEnd() != 
                   (it = history_->get_change_nts(next_seq, ..., &aux_ch, it)))
            {
                aux_ch = *it;
                next_seq = aux_ch->sequenceNumber + 1;
                
                // 逐个通知新添加的 CacheChange
                listener->on_new_cache_change_added(this, aux_ch);
                
                // 重置迭代器(防止回调中失效)
                it = history_->changesBegin();
            }
        }
    }
}

4.3 InnerDataReaderListener 桥接

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl.cpp:924-937

复制代码
// DataReaderImpl 内部监听器,负责 RTPS → DDS 转换
void DataReaderImpl::InnerDataReaderListener::on_data_available(
    RTPSReader* /*reader*/,
    const GUID_t& writer_guid,
    const SequenceNumber_t& first_sequence,
    const SequenceNumber_t& last_sequence,
    bool& should_notify_individual_changes)
{
    should_notify_individual_changes = false;
    
    // 调用 DataReaderImpl 的处理逻辑
    if (data_reader_->on_data_available(
            writer_guid, first_sequence, last_sequence))
    {
        // 设置通信状态标志,触发用户 Listener
        data_reader_->set_read_communication_status(true);
    }
}

4.4 DataReaderImpl::on_data_available()

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl.cpp:1063-1083

复制代码
bool DataReaderImpl::on_data_available(
    const GUID_t& writer_guid,
    const SequenceNumber_t& first_sequence,
    const SequenceNumber_t& last_sequence)
{
    bool ret_val = false;
    
    // 加锁保护
    std::lock_guard<RecursiveTimedMutex> guard(reader_->getMutex());
    
    // 遍历序列号范围,更新每个样本的状态
    for (auto seq = first_sequence; seq <= last_sequence; ++seq)
    {
        CacheChange_t* change = nullptr;
        
        if (history_.get_change(seq, writer_guid, &change))
        {
            // 更新实例状态、Deadline、Lifespan 等
            ret_val |= on_new_cache_change_added(change);
        }
    }
    
    // 通知 ReadCondition(用于 WaitSet)
    try_notify_read_conditions();
    
    return ret_val;
}

4.5 触发用户 Listener 回调

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl.cpp:384-413

复制代码
void DataReaderImpl::set_read_communication_status(bool trigger_value)
{
    if (trigger_value)
    {
        auto user_reader = user_datareader_;
        
        // 1. 先检查 Subscriber 级别的监听器
        SubscriberListener* subscriber_listener =
            subscriber_->get_listener_for(StatusMask::data_on_readers());
        
        if (subscriber_listener != nullptr)
        {
            // Subscriber 级别优先处理
            subscriber_listener->on_data_on_readers(
                subscriber_->user_subscriber_);
        }
        else
        {
            // 2. 调用 DataReader 级别的监听器 ← 关键!
            DataReaderListener* listener = 
                get_listener_for(StatusMask::data_available());
            
            if (listener != nullptr)
            {
                // 这就是用户定义的 ListenerSubscriberApp::on_data_available()
                listener->on_data_available(user_reader);
            }
        }
    }
    
    // 3. 设置状态标志(用于 WaitSet 机制)
    StatusMask notify_status = StatusMask::data_on_readers();
    subscriber_->user_subscriber_->get_statuscondition()
        ->get_impl()->set_status(notify_status, trigger_value);
    
    notify_status = StatusMask::data_available();
    user_datareader_->get_statuscondition()
        ->get_impl()->set_status(notify_status, trigger_value);
}

关键点:

  • ✅ 支持两级 Listener:Subscriber 级和 DataReader 级
  • ✅ Subscriber 级优先(on_data_on_readers
  • ✅ 同时设置状态标志,支持 WaitSet 机制

5. Listener 模式详解

5.1 通知与获取分离的设计哲学

Fast-DDS 采用通知与获取分离的设计,这是理解 Listener 模式的关键。

两个核心环节
环节 函数 职责 触发方式
通知 on_data_available(reader) 告知应用"有数据到达" 框架自动触发
获取 reader->take_next_sample() 从 History 取出实际数据 用户主动调用
为什么这样设计?
  1. 灵活性: 应用可以决定何时、如何获取数据
  2. 批量处理 : 可以在回调中使用 while 循环一次性读取多个样本
  3. 错误处理 : 可以检查 take() 的返回值,处理异常情况
  4. 零拷贝支持: 可以使用 loaned samples 避免内存拷贝

5.2 HelloWorld 示例代码分析

文件位置 : examples/cpp/hello_world/ListenerSubscriberApp.cpp:127-142

复制代码
// 1. 创建 DataReader 时注册 Listener
reader_ = subscriber_->create_datareader(
    topic_, 
    reader_qos, 
    this,              // ← 传入 this 作为 Listener
    StatusMask::all());

// 2. 用户定义的回调函数
void ListenerSubscriberApp::on_data_available(DataReader* reader)
{
    SampleInfo info;
    
    // 3. 在回调中主动调用 take_next_sample 获取数据
    while ((!is_stopped()) && 
           (RETCODE_OK == reader->take_next_sample(&hello_, &info)))
    {
        if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data)
        {
            received_samples_++;
            
            // 4. 处理数据
            std::cout << "Message: '" << hello_.message() 
                      << "' with index: '" << hello_.index()
                      << "' RECEIVED" << std::endl;
            
            if (samples_ > 0 && (received_samples_ >= samples_))
            {
                stop();
            }
        }
    }
}
关键要点

常见误解 : 认为 on_data_available() 会直接传递数据

实际情况 : on_data_available() 只是通知信号,必须主动调用 take() 获取数据


5.3 串联关系图解

复制代码
┌─────────────────────────────────────────────────────────┐
│  RTPS 层: StatefulReader::NotifyChanges()               │
│      ↓                                                   │
│  调用 InnerDataReaderListener::on_data_available()      │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│  DDS 层: DataReaderImpl::on_data_available()            │
│      ↓                                                   │
│  调用 set_read_communication_status(true)               │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│  触发用户回调                                              │
│      ↓                                                   │
│  listener->on_data_available(user_reader)               │
│      ↓                                                   │
│  ┌───────────────────────────────────────────────────┐  │
│  │ 用户代码: ListenerSubscriberApp                   │  │
│  │                                                   │  │
│  │  void on_data_available(DataReader* reader) {    │  │
│  │      // 此时还没有数据!                           │  │
│  │                                                   │  │
│  │      // 必须主动调用 take_next_sample             │  │
│  │      while(reader->take_next_sample(&hello_,     │  │
│  │                                   &info)) {      │  │
│  │          // 现在才有数据                           │  │
│  │          cout << hello_.message();               │  │
│  │      }                                           │  │
│  │  }                                               │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

6. 高性能优化机制

6.1 栈上分配:StackAllocatedSequence

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl.cpp:763-765

复制代码
// 传统方式(堆分配)
std::vector<void*> data_values(1);  // malloc + 可能的扩容

// Fast-DDS 优化(栈上分配)
StackAllocatedSequence<void*, 1> data_values;  // 栈上固定容量
const_cast<void**>(data_values.buffer())[0] = data;

优势:

  • ✅ 避免 new/malloc 系统调用开销
  • ✅ 确定性内存布局,提高缓存命中率
  • ✅ 自动生命周期管理,无需手动释放

适用场景: 单样本或少量样本的高频操作


6.2 命令模式:ReadTakeCommand

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl/ReadTakeCommand.hpp

复制代码
// 创建命令对象
detail::StateFilter states{ NOT_READ_SAMPLE_STATE, ANY_VIEW_STATE, ANY_INSTANCE_STATE };
detail::ReadTakeCommand cmd(
    *this,              // DataReaderImpl 引用
    data_values,        // 数据缓冲区
    sample_infos,       // 元信息缓冲区
    1,                  // max_samples
    states,             // 状态过滤器
    it.second,          // 实例句柄
    false,              // exact_instance
    false);             // single_instance

// 执行命令
while (!cmd.is_finished())
{
    cmd.add_instance(should_take);  // should_take=true 表示 take
}

封装的复杂逻辑:

  1. 多实例遍历
  2. 内容过滤(QueryCondition)
  3. QoS 策略应用(Deadline、Lifespan 等)
  4. 资源限制检查
  5. read/take 语义统一

设计优势:

  • ✅ 单一职责:命令对象专注数据获取逻辑
  • ✅ 可扩展:易于添加新的过滤条件或 QoS 策略
  • ✅ 可测试:命令对象可独立单元测试

6.3 线程安全:递归互斥锁

文件位置 : src/cpp/fastdds/subscriber/DataReaderImpl.cpp:750-752

复制代码
#if HAVE_STRICT_REALTIME
    // 严格实时模式:带超时时间的尝试锁定
    auto max_blocking_time = std::chrono::steady_clock::now() +
        std::chrono::microseconds(
            ::TimeConv::Time_t2MicroSecondsInt64(
                qos_.reliability().max_blocking_time));
    
    std::unique_lock<RecursiveTimedMutex> lock(
        reader_->getMutex(), std::defer_lock);
    
    if (!lock.try_lock_until(max_blocking_time))
    {
        return RETCODE_TIMEOUT;
    }
#else
    // 普通模式:直接锁定
    std::lock_guard<RecursiveTimedMutex> _(reader_->getMutex());
#endif

特点:

  • ✅ 递归锁:允许同一线程多次锁定(避免死锁)
  • ✅ 超时控制:严格实时模式下符合 QoS 要求
  • ✅ 细粒度锁定:仅保护 History 访问,不影响其他操作

6.4 read vs take 语义对比

操作 行为 History 变化 适用场景
read 复制样本数据 样本保留,标记为已读 需要多次读取或 peek 数据
take 复制样本数据 样本从 History 移除 数据处理后不再需要

示例:

复制代码
// read: 数据仍在 History 中
reader->read_next_sample(&data, &info);  // 可以再次 read

// take: 数据从 History 移除
reader->take_next_sample(&data, &info);  // 不能再次 take

7. 完整时序图

7.1 简化版时序图

复制代码
Publisher → Network → ASIO → UDPChannel
                                    ↓
                          ReceiverResource::OnDataReceived()
                                    ↓
                          MessageReceiver::processCDRMsg()
                                    ↓
                          【分支1】switch(submessageId)
                                    ↓
                          【分支2】安全/非安全路径
                                    ↓
                          【分支3】Stateful/Stateless Reader
                                    ↓
                          StatefulReader::change_received()
                                    ↓
                          history_->received_change()
                                    ↓
                          NotifyChanges()
                                    ↓
                          InnerDataReaderListener::on_data_available()
                                    ↓
                          DataReaderImpl::on_data_available()
                                    ↓
                          set_read_communication_status(true)
                                    ↓
                          listener->on_data_available(reader)  ← 用户回调
                                    ↓
                          reader->take_next_sample(&data, &info)  ← 用户主动获取
                                    ↓
                          ReadTakeCommand::add_instance()
                                    ↓
                          从 History 取出 + 反序列化 CDR
                                    ↓
                          用户处理数据

7.2 详细版时序图(含组件交互)

复制代码
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────────┐
│Publisher │    │  Network │    │   ASIO   │    │UDPChannel    │
│          │    │          │    │  Socket  │    │Resource      │
└────┬─────┘    └────┬─────┘    └────┬─────┘    └──────┬───────┘
     │               │               │                  │
     │──write()──▶   │               │                  │
     │               │──Packet──▶    │                  │
     │               │               │──recv_from()──▶  │
     │               │               │                  │
     │               │               │                  │──OnDataReceived()──▶
     │               │               │                  │
┌────▼───────────────▼───────────────▼──────────────────▼──────────────┐
│                        RTPS Protocol Layer                            │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ MessageReceiver::processCDRMsg()                             │   │
│  │   ├─ 解析 RTPS 头部                                           │   │
│  │   └─ 【分支1】switch(submessageId)                           │   │
│  │       └─ DATA → proc_Submsg_Data()                           │   │
│  │           ↓                                                   │   │
│  │       【分支2】process_data_message_function_                 │   │
│  │           └─ findAllReaders()                                │   │
│  │               ↓                                               │   │
│  │       【分支3】BaseReader::process_data_msg() (多态)          │   │
│  │           └─ StatefulReader::process_data_msg()              │   │
│  └──────────────────────────────────────────────────────────────┘   │
│                              │                                       │
│                              ▼                                       │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ StatefulReader::change_received()                            │   │
│  │   ├─ acceptMsgFrom() → WriterProxy                           │   │
│  │   ├─ change_pool_->reserve_cache()                           │   │
│  │   ├─ payload_pool_->get_payload()                            │   │
│  │   └─ history_->received_change()                             │   │
│  │       ↓                                                       │   │
│  │   NotifyChanges()                                            │   │
│  │       ↓                                                       │   │
│  │   InnerDataReaderListener::on_data_available()               │   │
│  └──────────────────────────────────────────────────────────────┘   │
└──────────────────────────────┬──────────────────────────────────────┘
                               │
                               ▼
┌──────────────────────────────────────────────────────────────────────┐
│                        DDS Application Layer                          │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │ DataReaderImpl::on_data_available()                          │   │
│  │   ├─ on_new_cache_change_added() → 更新实例状态               │   │
│  │   └─ set_read_communication_status(true)                     │   │
│  │       ↓                                                       │   │
│  │   【触发用户回调】                                             │   │
│  │   listener->on_data_available(user_datareader_)              │   │
│  │       ↓                                                       │   │
│  │   ┌──────────────────────────────────────────────────────┐   │   │
│  │   │ 用户代码: ListenerSubscriberApp                      │   │   │
│  │   │                                                       │   │   │
│  │   │  void on_data_available(DataReader* reader) {        │   │   │
│  │   │      while(reader->take_next_sample(&hello_, &info)){│   │   │
│  │   │          // 处理数据                                   │   │   │
│  │   │      }                                               │   │   │
│  │   │  }                                                   │   │   │
│  │   └──────────────────────────────────────────────────────┘   │   │
│  │       ↓                                                       │   │
│  │   DataReaderImpl::read_or_take_next_sample()                 │   │
│  │       ├─ 加锁 (RecursiveTimedMutex)                          │   │
│  │       ├─ lookup_available_instance()                         │   │
│  │       ├─ ReadTakeCommand 执行 take 操作                       │   │
│  │       │   ├─ 从 History 取出 CacheChange                     │   │
│  │       │   ├─ 反序列化 CDR 数据                                │   │
│  │       │   └─ 填充 SampleInfo                                 │   │
│  │       └─ try_notify_read_conditions()                        │   │
│  └──────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────────┘

8. 关键代码位置索引

网络层

文件 行号 函数 说明
src/cpp/rtps/transport/UDPChannelResource.cpp 78 perform_listen_operation() ASIO 异步接收
src/cpp/rtps/network/ReceiverResource.h 53-57 OnDataReceived() 传递给 RTPS 层

RTPS 协议层

分支 1:子消息分发
文件 行号 函数 说明
src/cpp/rtps/messages/MessageReceiver.cpp 420-580 processCDRMsg() 主解析函数
src/cpp/rtps/messages/MessageReceiver.cpp 740-900 proc_Submsg_Data() DATA 消息处理
分支 2:安全/非安全
文件 行号 函数 说明
src/cpp/rtps/messages/MessageReceiver.cpp 68-105 构造函数 函数指针初始化
src/cpp/rtps/messages/MessageReceiver.cpp 221-232 process_data_message_without_security() 非安全路径
src/cpp/rtps/messages/MessageReceiver.cpp 127-167 process_data_message_with_security() 安全路径
分支 3:Reader 多态
文件 行号 函数 说明
src/cpp/rtps/reader/StatefulReader.cpp 567-700 process_data_msg() RELIABLE 实现
src/cpp/rtps/reader/StatelessReader.cpp - process_data_msg() BEST_EFFORT 实现
src/cpp/rtps/reader/StatefulReader.cpp 1085-1230 change_received() 添加到 History
src/cpp/rtps/reader/StatefulReader.cpp 1236-1300 NotifyChanges() 通知 Listener

DDS 应用层

文件 行号 函数 说明
src/cpp/fastdds/subscriber/DataReaderImpl.cpp 924-937 InnerDataReaderListener::on_data_available() RTPS→DDS 桥接
src/cpp/fastdds/subscriber/DataReaderImpl.cpp 1063-1083 DataReaderImpl::on_data_available() 更新实例状态
src/cpp/fastdds/subscriber/DataReaderImpl.cpp 384-413 set_read_communication_status() 触发用户回调
src/cpp/fastdds/subscriber/DataReaderImpl.cpp 730-780 read_or_take_next_sample() 从 History 获取数据
examples/cpp/hello_world/ListenerSubscriberApp.cpp 127-142 on_data_available() 用户回调示例

9. 总结

核心设计思想

  1. 三层架构: 网络层、RTPS 协议层、DDS 应用层职责清晰
  2. 三处分支: 子消息类型、安全配置、可靠性策略决定处理路径
  3. 通知与获取分离 : on_data_available() 通知,take() 主动获取
  4. 高性能优化: 栈上分配、命令模式、线程安全锁

学习建议

  1. 从示例入手: 先运行 HelloWorld 示例,观察 Listener 回调
  2. 逐层深入: 从应用层 → RTPS 层 → 网络层,理解每层职责
  3. 关注分支: 重点理解三处分支的决策逻辑
  4. 实践验证: 修改 QoS 策略,观察不同 Reader 的行为差异

延伸阅读


文档版本 : v1.0
最后更新 : 2026-05-17
适用 Fast-DDS 版本: v3.5.0

相关推荐
闲人编程1 小时前
Agent的评估体系(AgentEval):如何判断一个Agent好坏?
大数据·人工智能·python·算法·agent·智能体·swe
hnult1 小时前
知识竞赛考试平台怎么选?2026 考试云全功能选型与实践指南
大数据·人工智能
tzc_fly1 小时前
Latent-Y:经实验室验证的从头药物设计自主智能体
人工智能
weixin_446260852 小时前
hermes agent的版本更新与web控制台
人工智能
瑞华丽PLM2 小时前
瑞华丽 AI 智能体研发数字化实战指南
人工智能·cae·工业软件·仿真软件·国产软件·瑞华丽plm·瑞华丽
MediaTea2 小时前
AI 术语通俗词典:logits
人工智能
摄影图2 小时前
神经网络创意科技图片素材 满足多场景科技设计创作需求
人工智能·科技·神经网络·aigc·插画
沫璃染墨2 小时前
红黑树完全指南:从核心原理到插入验证全实现
开发语言·c++·算法
Leweslyh2 小时前
【论文翻译】意图驱动的多智能体大语言模型网络管理:Confucius框架
人工智能·语言模型·自然语言处理