3. 数组与序列消息

数组与序列消息 学习卡片

任务目标

在FastDDS中,IDL支持两种批量数据类型:固定数组(定长,编译期确定)与可变序列(动态长度,运行时确定)。本案例将定义同时包含这两种字段的消息类型,并完成一个发布-订阅闭环,验证数据正确传输。

IDL定义

创建 ArraySeq.idl:

struct ArraySeqMessage
{
    long fixed_array[4];        // 固定数组,长度4
    sequence<long> dynamic_seq; // 可变序列,长度不限
};

完整实现代码

以下为单个可编译运行的C++源文件,包含发布端与订阅端逻辑(使用FastDDS 2.x API):

#include <iostream>
#include <thread>
#include <chrono>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/subscriber/Subscriber.hpp>
#include <fastdds/dds/subscriber/DataReader.hpp>
#include <fastdds/dds/subscriber/SampleInfo.hpp>
#include "ArraySeqPubSubTypes.h"  // 由fastddsgen生成

using namespace eprosima::fastdds::dds;

class SubListener : public DataReaderListener
{
public:
    bool received = false;
    void on_data_available(DataReader* reader) override
    {
        ArraySeqMessage msg;
        SampleInfo info;
        while (reader->take_next_sample(&msg, &info) == ReturnCode_t::RETCODE_OK)
        {
            if (info.valid_data)
            {
                std::cout << "收到消息: fixed_array = [";
                for (int i = 0; i < 4; ++i)
                    std::cout << msg.fixed_array()[i] << (i < 3 ? ", " : "");
                std::cout << "], dynamic_seq = [";
                for (auto it = msg.dynamic_seq().begin(); it != msg.dynamic_seq().end(); ++it)
                    std::cout << *it << (std::next(it) != msg.dynamic_seq().end() ? ", " : "");
                std::cout << "]" << std::endl;
                received = true;
            }
        }
    }
};

int main()
{
    // 创建参与者
    DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0);
    if (!participant) return -1;

    // 注册类型
    TypeSupport type(new ArraySeqMessagePubSubType());
    type.register_type(participant);

    // 创建主题
    Topic* topic = participant->create_topic("ArraySeqTopic", type.get_type_name(), TOPIC_QOS_DEFAULT);

    // 创建发布端
    Publisher* pub = participant->create_publisher(PUBLISHER_QOS_DEFAULT);
    DataWriter* writer = pub->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);

    // 创建订阅端
    Subscriber* sub = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
    SubListener listener;
    DataReader* reader = sub->create_datareader(topic, DATAREADER_QOS_DEFAULT, &listener);

    // 等待匹配
    std::this_thread::sleep_for(std::chrono::seconds(1));

    // 构造并发送消息
    ArraySeqMessage msg;
    for (int i = 0; i < 4; ++i)
        msg.fixed_array()[i] = i * 10;  // 0, 10, 20, 30
    msg.dynamic_seq().resize(3);
    msg.dynamic_seq()[0] = 100;
    msg.dynamic_seq()[1] = 200;
    msg.dynamic_seq()[2] = 300;

    writer->write(&msg);
    std::cout << "已发送消息" << std::endl;

    // 等待接收
    for (int i = 0; i < 10 && !listener.received; ++i)
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

    // 清理
    participant->delete_contained_entities();
    DomainParticipantFactory::get_instance()->delete_participant(participant);

    return listener.received ? 0 : -1;
}

编译与运行

  1. 使用 fastddsgen ArraySeq.idl 生成辅助代码(含 ArraySeqPubSubTypes.h/cpp)。
  2. 编译(以g++为例):
g++ -std=c++11 main.cpp ArraySeq.cxx ArraySeqPubSubTypes.cxx \
    -I$FASTDDS_INCLUDE_DIR -L$FASTDDS_LIB_DIR \
    -lfastdds -lfastcdr -o array_seq_demo
  1. 运行:./array_seq_demo

验证方法

程序启动后,发布端发送一条消息,订阅端在同一进程内接收。观察标准输出:

已发送消息
收到消息: fixed_array = [0, 10, 20, 30], dynamic_seq = [100, 200, 300]

若输出与上述一致且进程退出码为0,则说明固定数组与可变序列均正确传输。若需跨进程验证,可将发布与订阅拆分为两个独立程序,分别运行于同一域(Domain ID=0)即可。

关键说明

  • 固定数组在生成的C++类型中映射为 std::array<int32_t, 4>,通过 msg.fixed_array() 获取引用后按下标访问。
  • 可变序列映射为 std::vector<int32_t>,使用前需 resize() 或 push_back() 分配长度。
  • 本示例发布与订阅在同一进程,便于单文件验证;实际部署时两端可运行在不同主机,仅需保证Domain ID与Topic名称一致。