FastDDS跨网段通信全解析:方法对比、云端部署与实战配置

在工业物联网、智能机器人协同、车载设备互联等场景中,设备常跨网段(甚至跨公网)部署,数据的实时、可靠传输成为核心需求。FastDDS(基于DDS标准的开源实现)作为工业级实时通信协议,凭借低延迟、高吞吐量、丰富QoS能力,成为跨网段通信的优选方案。

本文将从「跨网段通信方法选型」切入,详细讲解云端服务器FastDDS环境部署、Discovery Server配置、本地/远端发布订阅参数配置,最后通过实战案例验证通信效果,帮你快速搞定FastDDS跨网段落地。

一、FastDDS跨网段通信常用方法对比

跨网段场景下,FastDDS主流通信方案有4种,需根据实时性、部署成本、设备资源选型,以下是核心对比(附适用场景):

通信方案 核心原理 实时性 部署复杂度 运维成本 适用场景
Discovery Server(原生方案) 部署中心DS节点,跨网段设备通过DS完成节点发现,数据P2P直连 高(微秒-毫秒级) 中(需配置DS+端口放行) 低(仅维护DS节点) 工业控制、机器人协同、高频数据传输
MQTT转发方案 放弃FastDDS原生发现,通过MQTT Broker转发数据(FastDDS→MQTT协议转换) 中(毫秒-秒级) 低(部署MQTT Broker即可) 中(维护Broker+协议转换网关) 低资源设备、跨生态通信、轻量监控
FastDDS+MQTT混合架构 同网段用FastDDS保证实时性,跨网段通过MQTT网关转发数据 中高(本地实时+跨网段低延迟) 高(维护DS+Broker+网关) 中高(多组件协同) 本地集群+跨厂区通信、混合设备场景
VPN专线方案 通过VPN将跨网段设备接入同一虚拟局域网,FastDDS按局域网方式通信 高(接近局域网性能) 高(部署VPN服务器+设备接入) 高(VPN带宽+运维) 高安全需求、对实时性要求极高的场景
选型结论:若无需跨生态、追求实时性,优先选「Discovery Server原生方案」(本文重点讲解);若设备资源有限、需快速上线,可选「MQTT转发方案」;安全优先则考虑VPN专线。

二、云端服务器FastDDS环境部署(以阿里云/腾讯云为例)

跨网段通信的核心是部署「云端Discovery Server(DS)」,作为跨网段设备的发现中心。以下步骤基于 Ubuntu 20.04 系统(CentOS 操作类似),云服务器IP以 00.00.00.00 为例。

2.1 环境依赖安装

FastDDS依赖C++11及以上、CMake、Boost等工具,执行以下命令安装:


# 更新软件源
sudo apt update && sudo apt upgrade -y

# 安装基础依赖
sudo apt install -y build-essential cmake git libboost-all-dev libssl-dev

# 安装Python依赖(用于FastDDS工具)
sudo apt install -y python3-pip python3-colcon-common-extensions

2.2 FastDDS编译安装(最新稳定版2.12.0)

FastDDS推荐源码编译安装,确保功能完整:


# 克隆源码(指定稳定版)
git clone -b 2.12.0 https://github.com/eProsima/Fast-DDS.git
cd Fast-DDS
mkdir build && cd build

# 编译配置(默认安装到/usr/local)
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..

# 编译安装(-j后面跟CPU核心数,加速编译)
make -j4
sudo make install

# 验证安装(查看版本)
fastdds --version

若输出 eProsima Fast DDS x.x.x ,说明安装成功。

2.3 云服务器网络配置(关键!)

跨网段通信需放行FastDDS核心端口,云服务器需配置「操作系统防火墙」和「云平台安全组」:

2.3.1 操作系统防火墙放行端口

# 放行DS发现端口(默认11811,TCP/UDP)
sudo firewall-cmd --add-port=11811/tcp --permanent
sudo firewall-cmd --add-port=11811/udp --permanent

# 放行用户数据端口(默认7400,TCP/UDP)
sudo firewall-cmd --add-port=7400/tcp --permanent
sudo firewall-cmd --add-port=7400/udp --permanent

# 重载防火墙规则
sudo firewall-cmd --reload

# 验证端口放行
sudo firewall-cmd --list-ports
2.3.2 云平台安全组配置

登录阿里云/腾讯云控制台,找到对应服务器的「安全组」→「入站规则」,添加两条规则:

  • 规则1:端口范围 11811,协议 TCP/UDP,源地址 0.0.0.0/0(测试用,生产环境可限定客户端网段)

  • 规则2:端口范围 7400,协议 TCP/UDP,源地址 0.0.0.0/0

⚠️ 注意:安全组配置是跨公网通信的关键,若未配置,客户端会无法连接DS服务器。

三、云端Discovery Server配置与服务启动

DS服务器需配置「禁用多播」「绑定公网IP」「指定端口」,避免配置冲突。

3.1 编写DS配置文件(ds_server_public.xml)

在云服务器上创建配置文件,路径建议 /home/ubuntu/fastdds_config/ds_server_public.xml,内容如下(关键参数有注释):


<?xml version="1.0" encoding="UTF-8" ?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///usr/local/share/fastdds/schema/fastdds.xsd">
    <profiles>
        <!-- 云端DS节点配置,默认配置文件 -->
        <participant profile_name="PublicDiscoveryServer" is_default_profile="true">
            <rtps>
                <!-- 公网MTU配置(避免IP分片) -->
                <mtu>1472</mtu>
                
                <builtin>
                    <discovery_config>
                        <!-- 禁用多播(跨网段多播会被路由阻断) -->
                        <multicast_enabled>false</multicast_enabled>
                        <!-- 清空静态对等节点(仅用DS发现) -->
                        <initial_peers_list clear="true"/>
                    </discovery_config>
                    
                    <!-- DS核心配置 -->
                    <discovery_server>
                        <enabled>true</enabled>
                        <server_id>0&lt;/server_id&gt; <!-- 服务器固定ID为0(超级节点) -->
                        <server_addresses>
                            <locator&gt;
                                &lt;tcpv4&gt; <!-- 公网优先用TCP,穿透性更强、丢包更少 -->
                                    &lt;address&gt;00.00.00.00&lt;/address&gt; <!-- 云服务器公网IP -->
                                    <port>11811</port><!-- DS默认端口 -->
                                </tcpv4>
                            </locator>
                        </server_addresses>
                    </discovery_server>
                </builtin>
                
                <!-- 传输层配置(仅保留TCP,跨网段无需共享内存SHM) -->
                <transports>
                    <transport_id>tcp_transport</transport_id>
                    <type>TCPv4</type>
                    <tcpv4>
                        <nagle_algorithm>false&lt;/nagle_algorithm&gt; <!-- 禁用Nagle算法,减少小包延迟 -->
                        <keep_alive>true</keep_alive><!-- 开启TCP保活,避免公网连接断开 -->
                    </tcpv4>
                </transports>
                
                <!-- 指定传输优先级(仅用TCP) -->
                <userTransports>
                    <transport_id>tcp_transport</transport_id>
                </userTransports>
                
                <!-- 用户数据传输端口 -->
                <default_unicast_port>7400</default_unicast_port>
            </rtps>
        </participant>
    </profiles>
</dds>

3.2 启动DS服务(后台常驻)

使用FastDDS自带工具启动DS,建议后台运行(避免终端关闭后进程退出):


# 后台启动DS,日志输出到ds_log.log
nohup fastdds discovery -i 0 -c /home/ubuntu/fastdds_config/ds_server_public.xml > /home/ubuntu/fastdds_config/ds_log.log 2>&1 &

# 验证DS进程是否运行
ps -ef | grep fastdds

# 验证端口是否监听
netstat -tulpn | grep 11811

若输出类似 tcp 0 0 00.00.00.00:11811 0.0.0.0:* LISTEN 12345/fastdds ,说明DS服务已正常启动并监听端口。

四、本地/远端程序配置(发布者/订阅者)

跨网段的客户端(本地电脑/远端设备)需配置「指向云端DS服务器」「禁用多播」「适配TCP传输」,发布者和订阅者配置类似,仅QoS可按需调整。

4.1 客户端通用配置文件(client_config.xml)

在本地/远端客户端创建配置文件,路径建议 ./fastdds_config/client_config.xml,内容如下:


<?xml version="1.0" encoding="UTF-8" ?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///usr/local/share/fastdds/schema/fastdds.xsd">
    <profiles>
        <!-- 客户端域参与者配置(发布者/订阅者共用) -->
        <participant profile_name="CrossNetworkClient" is_default_profile="true">
            <rtps>
                <mtu>1472</mtu>
                <builtin>
                    <discovery_config>
                        <multicast_enabled>false</multicast_enabled>
                        <initial_peers_list clear="true"/>
                    </discovery_config>
                    
                    <!-- 客户端DS配置,指向云端服务器 -->
                    <discovery_server>
                        <enabled>true</enabled>
                        &lt;server_id&gt;1&lt;/server_id&gt; <!-- 客户端ID必须非0,不同客户端可设为1、2、3... -->
                        <server_addresses>
                            <locator>
                                <tcpv4>
                                    <address&gt;00.00.00.00&lt;/address&gt; <!-- 云端DS公网IP -->
                                    <port&gt;11811&lt;/port&gt; <!-- 与DS端口一致 -->
                                </tcpv4>
                            </locator>
                        </server_addresses>
                    </discovery_server>
                    
                    <!-- 客户端DS超时配置(适配公网延迟) -->
                    <discovery_server_client>
                        <leaseDuration><sec>60</sec>&lt;/leaseDuration&gt; <!-- 租期60秒 -->
                        <leaseRenewal&gt;&lt;sec&gt;20&lt;/sec&gt;&lt;/leaseRenewal&gt; <!-- 提前20秒续租 -->
                        <connection_timeout>&lt;sec&gt;5&lt;/sec&gt;&lt;/connection_timeout&gt; <!-- 连接超时5秒 -->
                    </discovery_server_client>
                </builtin>
                
                <!-- 传输层配置(与DS一致,用TCP) -->
                <transports>
                    <transport_id>tcp_transport</transport_id>
                    <type>TCPv4</type>
                    <tcpv4>
                        <nagle_algorithm>false</nagle_algorithm>
                        <keep_alive>true</keep_alive>
                    </tcpv4>
                </transports>
                <userTransports>
                    <transport_id>tcp_transport</transport_id>
                </userTransports>
                <default_unicast_port>7400</default_unicast_port>
            </rtps>
        </participant>
        
        <!-- 发布者QoS配置(按需调整) -->
        <publisher profile_name="CrossNetworkPublisher" is_default_profile="true">
            <qos>
                <reliability><kind>RELIABLE_RELIABILITY_QOS</kind></reliability&gt; <!-- 可靠传输 -->
                <durability><kind>VOLATILE_DURABILITY_QOS</kind></durability> <!-- 无缓存,即时传输 -->
            </qos>
        </publisher>
        
        <!-- 订阅者QoS配置(与发布者一致,保证匹配) -->
        <subscriber profile_name="CrossNetworkSubscriber" is_default_profile="true">
            <qos>
                <reliability><kind>RELIABLE_RELIABILITY_QOS</kind></reliability>
                <durability><kind>VOLATILE_DURABILITY_QOS</kind></durability>
            </qos>
        </subscriber>
        
        <!-- 数据写入者(发布者)配置 -->
        <data_writer profile_name="CrossNetworkDataWriter" is_default_profile="true">
            <qos>
                <history>
                    <kind>KEEP_LAST_HISTORY_QOS</kind&gt;
                    &lt;depth&gt;1&lt;/depth&gt; <!-- 仅保留最新1条数据,减少延迟 -->
                </history>
                <reliability>
                    <kind>RELIABLE_RELIABILITY_QOS</kind>
                    <max_blocking_time>&lt;nanosec&gt;50000000&lt;/nanosec&gt;&lt;/max_blocking_time&gt; <!-- 阻塞上限50ms -->
                </reliability>
            </qos>
        </data_writer>
        
        <!-- 数据读取者(订阅者)配置 -->
        <data_reader profile_name="CrossNetworkDataReader" is_default_profile="true">
            <qos>
                <history><kind>KEEP_LAST_HISTORY_QOS</kind><depth>1</depth></history>
                <reliability><kind>RELIABLE_RELIABILITY_QOS</kind></reliability>
            </qos>
        </data_reader>
    </profiles>
</dds>

4.2 发布者/订阅者程序开发(C++示例)

FastDDS程序需包含「类型定义」「域参与者创建」「发布/订阅初始化」,核心是加载上述配置文件。以下是简化示例(假设自定义消息类型为 HelloWorld):

4.2.1 发布者程序(publisher.cpp)

#include "HelloWorldPubSubTypes.h"
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/topic/Topic.hpp>
#include <fastdds/dds/data_writer/DataWriter.hpp>

using namespace eprosima::fastdds::dds;

int main()
{
    // 1. 加载配置文件(关键:指定客户端配置)
    DomainParticipantFactory::get_instance()->load_XML_profiles("fastdds_config/client_config.xml");
    
    // 2. 创建域参与者(使用默认配置)
    DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
    if (participant == nullptr) return -1;
    
    // 3. 注册消息类型
    HelloWorldPubSubType type;
    participant->register_type(&type);
    
    // 4. 创建主题(主题名需与订阅者一致)
    Topic* topic = participant->create_topic("HelloWorldTopic", type.get_type_name(), TOPIC_QOS_DEFAULT);
    if (topic == nullptr) return -1;
    
    // 5. 创建发布者
    Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT);
    if (publisher == nullptr) return -1;
    
    // 6. 创建数据写入者
    DataWriter* writer = publisher->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);
    if (writer == nullptr) return -1;
    
    // 7. 循环发布数据
    HelloWorld msg;
    int count = 0;
    while (true)
    {
        msg.message("Hello FastDDS Cross Network! Count: " + std::to_string(count++));
        writer->write(&msg);
        std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 每秒发布一次
    }
    
    // 8. 资源释放(实际项目中需处理退出逻辑)
    participant->delete_publisher(publisher);
    participant->delete_topic(topic);
    DomainParticipantFactory::get_instance()->delete_participant(participant);
    return 0;
}
4.2.2 订阅者程序(subscriber.cpp)

#include "HelloWorldPubSubTypes.h"
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/subscriber/Subscriber.hpp>
#include <fastdds/dds/topic/Topic.hpp>
#include <fastdds/dds/data_reader/DataReader.hpp>
#include <fastdds/dds/data_reader/DataReaderListener.hpp>

using namespace eprosima::fastdds::dds;

// 监听类:处理接收的数据
class SubListener : public DataReaderListener
{
public:
    void on_data_available(DataReader* reader) override
    {
        HelloWorld msg;
        SampleInfo info;
        if (reader->take_next_sample(&msg, &info) == ReturnCode_t::RETCODE_OK && info.valid_data)
        {
            std::cout << "Received message: " << msg.message() << std::endl;
        }
    }
};

int main()
{
    // 1. 加载配置文件
    DomainParticipantFactory::get_instance()->load_XML_profiles("fastdds_config/client_config.xml");
    
    // 2. 创建域参与者
    DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);
    if (participant == nullptr) return -1;
    
    // 3. 注册消息类型
    HelloWorldPubSubType type;
    participant->register_type(&type);
    
    // 4. 创建主题(与发布者主题名一致)
    Topic* topic = participant->create_topic("HelloWorldTopic", type.get_type_name(), TOPIC_QOS_DEFAULT);
    if (topic == nullptr) return -1;
    
    // 5. 创建订阅者
    Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
    if (subscriber == nullptr) return -1;
    
    // 6. 创建数据读取者(绑定监听)
    SubListener listener;
    DataReader* reader = subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT, &listener);
    if (reader == nullptr) return -1;
    
    // 7. 阻塞等待数据
    std::cout << "Subscriber waiting for data..." << std::endl;
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    // 8. 资源释放
    participant->delete_subscriber(subscriber);
    participant->delete_topic(topic);
    DomainParticipantFactory::get_instance()->delete_participant(participant);
    return 0;
}

4.3 编译运行(CMakeLists.txt简化配置)


cmake_minimum_required(VERSION 3.10)
project(FastDDS_Cross_Network)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找FastDDS依赖
find_package(fastcdr REQUIRED)
find_package(fastrtps REQUIRED)

# 生成消息类型文件(HelloWorld.idl编译生成)
add_custom_command(
    OUTPUT HelloWorldPubSubTypes.cpp HelloWorldPubSubTypes.h
    COMMAND fastddsgen -cs -cpp HelloWorld.idl
    DEPENDS HelloWorld.idl
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

# 发布者可执行文件
add_executable(publisher publisher.cpp HelloWorldPubSubTypes.cpp)
target_link_libraries(publisher fastrtps fastcdr)

# 订阅者可执行文件
add_executable(subscriber subscriber.cpp HelloWorldPubSubTypes.cpp)
target_link_libraries(subscriber fastrtps fastcdr)

编译运行命令:


# 创建build目录
mkdir build && cd build

# 编译
cmake .. && make -j4

# 运行订阅者(本地/远端设备)
./subscriber

# 运行发布者(另一台跨网段设备)
./publisher

五、实战测试与问题排查

5.1 正常通信现象

  • 订阅者终端输出:Subscriber waiting for data... 后,陆续收到Received message: Hello FastDDS Cross Network! Count: 0,1,2...

  • 云端DS日志(ds_log.log)无报错,出现 Client connected 相关日志

5.2 常见问题排查

问题1:客户端无法连接DS服务器

排查步骤:

  1. ping 00.00.00.00验证公网可达

  2. telnet 00.00.00.00 11811 验证端口是否通(通则返回 Connected)

  3. 检查云服务器安全组是否放行11811端口

  4. 检查DS配置文件中 address 是否为云服务器公网IP(而非内网IP/127.0.0.1)

问题2:能连接DS,但收不到数据

排查步骤:

  1. 确认发布者/订阅者主题名一致(本文为 HelloWorldTopic)

  2. 确认QoS匹配(可靠性、持久性策略一致)

  3. 检查客户端配置文件中 transport 与DS一致(均为TCP)

  4. 用 fastdds monitor 工具可视化查看节点是否正常发现

问题3:公网通信卡顿/丢包

解决方案:

  1. 增大客户端 leaseDuration 租期(如改为120秒)

  2. 调整可靠性策略的 max_retry_count(最多3次重传)

  3. 启用数据压缩(参考前文实时性优化配置)

六、总结与优化建议

FastDDS跨网段通信的核心是「Discovery Server+TCP传输」,其优势在于实时性和可靠性,适合工业级场景。本文通过“云端DS部署→客户端配置→实战测试”的完整流程,帮你快速落地跨网段通信。

进阶优化建议:

  • 传输层:若公网延迟低、丢包少,可改用 UDP-Lite 进一步降低延迟

  • QoS:实时性优先场景,将可靠性策略改为 BEST_EFFORT_RELIABILITY_QOS(无重传)

  • 监控:用 FastDDS Monitor 工具实时监控延迟、丢包率,动态调整配置

  • 安全:公网场景可启用 FastDDS 加密功能(配置 TLS/SSL),防止数据泄露

通过本文配置,FastDDS跨公网端到端延迟可控制在50-100ms,满足大多数工业实时通信需求。如果需要更极致的实时性,可考虑云服务器就近部署或专线网络。

(注:文档部分内容可能由 AI 生成)

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐