FastDDS之进程内通信

目录


本文主要记录Fast DDS中进程内通信的原理和流程。

Fast DDS 允许在同一进程内的实体之间加快通信,避免了传输层带来的任何开销。进程内通信通过发布者(Publisher)直接调用订阅者(Subscriber)的接收函数,不仅避免了传输过程中的数据复制或发送操作,还确保了消息能够被订阅者接收到,从而绕过了确认机制。
进程内的通信默认是开启的,也可以通过配置XML开启。有三个值:

  • INTRAPROCESS_OFF: 关闭该功能
  • INTRAPROCESS_USER_DATA_ONLY: 发现的元数据仍然使用普通的传输方式。
  • INTRAPROCESS_FULL: 默认值,业务数据和服务发现数据都使用进程内传输(TODO:服务发现怎么使用进程内通信?)

xml配置格式如下:

<library_settings>
    <intraprocess_delivery>FULL</intraprocess_delivery> <!-- OFF | USER_DATA_ONLY | FULL -->
</library_settings>

Fast DDS 使用DomainParticipant的GuidPrefix_t来识别在同一进程中运行的对等方。如果两个参与者的GuidPrefix_t前8个字节相同,则认为它们运行在同一进程中,因此会使用进程内传递。API:is_on_same_process_as()可以判断是否在同一进程内。

待确认:Fast DDS根据主机的多个参数来分配GUID前缀,其中一个参数就是当前启用的网络接口。如果在网络运行过程中网络接口有所更改,那么新创建的DomainParticipant将会得到一个新的GUID前缀,并且系统会认为它是在不同的主机上运行。

一个使用进程内通信的subscriber接收堆栈如下:

#0  learning_dds::DDSSubscriber::SubListener::on_data_available (this=0x7ffeaee77308, reader=0x6088ac321dc0) at /FastDDS/examples/cpp/dds/HelloFastDDS/DDSSubscriber.cpp:335
#1  0x0000763e9b9cea05 in eprosima::fastdds::dds::DataReaderImpl::InnerDataReaderListener::on_data_available (this=0x6088ac322730, writer_guid=..., first_sequence=..., last_sequence=...,
    should_notify_individual_changes=@0x763e90bfe73e: false) at /FastDDS/src/cpp/fastdds/subscriber/DataReaderImpl.cpp:918
#2  0x0000763e9b883641 in eprosima::fastrtps::rtps::StatefulReader::NotifyChanges (this=0x6088ac331f30, prox=0x763e68001480) at /FastDDS/src/cpp/rtps/reader/StatefulReader.cpp:1231
#3  0x0000763e9b883199 in eprosima::fastrtps::rtps::StatefulReader::change_received (this=0x6088ac331f30, a_change=0x6088ac338d50, prox=0x763e68001480, unknown_missing_changes_up_to=0)
    at /FastDDS/src/cpp/rtps/reader/StatefulReader.cpp:1162
#4  0x0000763e9b880daa in eprosima::fastrtps::rtps::StatefulReader::processDataMsg (this=0x6088ac331f30, change=0x6088ac1f0270) at /FastDDS/src/cpp/rtps/reader/StatefulReader.cpp:651
#5  0x0000763e9b7be99b in eprosima::fastrtps::rtps::StatefulWriter::intraprocess_delivery (this=0x6088ac1f0a40, change=0x6088ac1f0270, reader_proxy=0x763e400017d0)
    at /FastDDS/src/cpp/rtps/writer/StatefulWriter.cpp:475
#6  0x0000763e9b7bf6c5 in eprosima::fastrtps::rtps::StatefulWriter::deliver_sample_to_intraprocesses (this=0x6088ac1f0a40, change=0x6088ac1f0270)
    at /FastDDS/src/cpp/rtps/writer/StatefulWriter.cpp:634
#7  0x0000763e9b7c6d4f in eprosima::fastrtps::rtps::StatefulWriter::deliver_sample_nts (this=0x6088ac1f0a40, cache_change=0x6088ac1f0270, group=..., locator_selector=..., max_blocking_time=...)
    at /FastDDS/src/cpp/rtps/writer/StatefulWriter.cpp:2186
#8  0x0000763e9bceba56 in eprosima::fastdds::rtps::FlowControllerImpl<eprosima::fastdds::rtps::FlowControllerSyncPublishMode, eprosima::fastdds::rtps::FlowControllerFifoSchedule>::add_new_sample_impl<eprosima::fastdds::rtps::FlowControllerSyncPublishMode> (this=0x6088ac16bb40, writer=0x6088ac1f0a40, change=0x6088ac1f0270, max_blocking_time=...)
    at /FastDDS/src/cpp/rtps/flowcontrol/FlowControllerImpl.hpp:1190
#9  0x0000763e9bce8a44 in eprosima::fastdds::rtps::FlowControllerImpl<eprosima::fastdds::rtps::FlowControllerSyncPublishMode, eprosima::fastdds::rtps::FlowControllerFifoSchedule>::add_new_sample (
    this=0x6088ac16bb40, writer=0x6088ac1f0a40, change=0x6088ac1f0270, max_blocking_time=...) at /FastDDS/src/cpp/rtps/flowcontrol/FlowControllerImpl.hpp:1011
#10 0x0000763e9b7be743 in eprosima::fastrtps::rtps::StatefulWriter::unsent_change_added_to_history (this=0x6088ac1f0a40, change=0x6088ac1f0270, max_blocking_time=...)
    at /FastDDS/src/cpp/rtps/writer/StatefulWriter.cpp:447
#11 0x0000763e9b801d0e in eprosima::fastrtps::rtps::WriterHistory::notify_writer (this=0x6088ac1ecd90, a_change=0x6088ac1f0270, max_blocking_time=...)
    at /FastDDS/src/cpp/rtps/history/WriterHistory.cpp:123
#12 0x0000763e9b975283 in eprosima::fastrtps::rtps::WriterHistory::add_change_with_commit_hook<eprosima::fastdds::dds::DataWriterImpl::perform_create_new_change(eprosima::fastrtps::rtps::ChangeKind_t, void*, eprosima::fastrtps::rtps::WriteParams&, const InstanceHandle_t&)::<lambda(eprosima::fastdds::dds::DataWriterImpl::CacheChange_t&)> >(eprosima::fastrtps::rtps::CacheChange_t *, eprosima::fastrtps::rtps::WriteParams &, struct {...}, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > >) (this=0x6088ac1ecd90,
    a_change=0x6088ac1f0270, wparams=..., pre_commit=..., max_blocking_time=...) at /FastDDS/include/fastdds/rtps/history/WriterHistory.h:208
#13 0x0000763e9b974ae0 in eprosima::fastdds::dds::DataWriterHistory::add_pub_change_with_commit_hook<eprosima::fastdds::dds::DataWriterImpl::perform_create_new_change(eprosima::fastrtps::rtps::ChangeKind_t, void*, eprosima::fastrtps::rtps::WriteParams&, const InstanceHandle_t&)::<lambda(eprosima::fastdds::dds::DataWriterImpl::CacheChange_t&)> >(eprosima::fastrtps::rtps::CacheChange_t *, eprosima::fastrtps::rtps::WriteParams &, struct {...}, std::unique_lock<std::recursive_timed_mutex> &, const std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > > &) (this=0x6088ac1ecd90, change=0x6088ac1f0270, wparams=..., pre_commit=..., lock=..., max_blocking_time=...) at /FastDDS/src/cpp/fastdds/publisher/DataWriterHistory.hpp:141
#14 0x0000763e9b96da02 in eprosima::fastdds::dds::DataWriterImpl::perform_create_new_change (this=0x6088ac1ec8a0, change_kind=eprosima::fastrtps::rtps::ALIVE, data=0x7ffeaef0a0a8, wparams=...,
    handle=...) at /FastDDS/src/cpp/fastdds/publisher/DataWriterImpl.cpp:993
#15 0x0000763e9b96e002 in eprosima::fastdds::dds::DataWriterImpl::create_new_change_with_params (this=0x6088ac1ec8a0, changeKind=eprosima::fastrtps::rtps::ALIVE, data=0x7ffeaef0a0a8, wparams=...)
    at /FastDDS/src/cpp/fastdds/publisher/DataWriterImpl.cpp:1067
#16 0x0000763e9b96d28d in eprosima::fastdds::dds::DataWriterImpl::create_new_change (this=0x6088ac1ec8a0, changeKind=eprosima::fastrtps::rtps::ALIVE, data=0x7ffeaef0a0a8)
    at /FastDDS/src/cpp/fastdds/publisher/DataWriterImpl.cpp:914
#17 0x0000763e9b96b78a in eprosima::fastdds::dds::DataWriterImpl::write (this=0x6088ac1ec8a0, data=0x7ffeaef0a0a8) at /FastDDS/src/cpp/fastdds/publisher/DataWriterImpl.cpp:594
#18 0x0000763e9b964d63 in eprosima::fastdds::dds::DataWriter::write (this=0x6088ac1ec840, data=0x7ffeaef0a0a8) at /FastDDS/src/cpp/fastdds/publisher/DataWriter.cpp:84
#19 0x00006088ab856185 in learning_dds::DDSPublisher::SimpleInfo_value (this=0x7ffeaef09b10) at /FastDDS/examples/cpp/dds/HelloFastDDS/DDSPublisher.cpp:302
#20 0x00006088ab855f7a in learning_dds::DDSPublisher::publish (this=0x7ffeaef09b10, waitForListener=false) at /FastDDS/examples/cpp/dds/HelloFastDDS/DDSPublisher.cpp:275
#21 0x00006088ab855e2f in learning_dds::DDSPublisher::runThread (this=0x7ffeaef09b10, sleep=1000) at /FastDDS/examples/cpp/dds/HelloFastDDS/DDSPublisher.cpp:250
#22 0x00006088ab8711ac in std::__invoke_impl<void, void (learning_dds::DDSPublisher::*)(unsigned int), learning_dds::DDSPublisher*, unsigned int> (
    __f=@0x6088ac2539e8: (void (learning_dds::DDSPublisher::*)(learning_dds::DDSPublisher * const, unsigned int)) 0x6088ab855dfc <learning_dds::DDSPublisher::runThread(unsigned int)>,
    __t=@0x6088ac2539e0: 0x7ffeaef09b10) at /usr/include/c++/11/bits/invoke.h:74
#23 0x00006088ab8710c6 in std::__invoke<void (learning_dds::DDSPublisher::*)(unsigned int), learning_dds::DDSPublisher*, unsigned int> (
    __fn=@0x6088ac2539e8: (void (learning_dds::DDSPublisher::*)(learning_dds::DDSPublisher * const, unsigned int)) 0x6088ab855dfc <learning_dds::DDSPublisher::runThread(unsigned int)>)
    at /usr/include/c++/11/bits/invoke.h:96
#24 0x00006088ab870fe5 in std::thread::_Invoker<std::tuple<void (learning_dds::DDSPublisher::*)(unsigned int), learning_dds::DDSPublisher*, unsigned int> >::_M_invoke<0ul, 1ul, 2ul> (
    this=0x6088ac2539d8) at /usr/include/c++/11/bits/std_thread.h:259
#25 0x00006088ab870f7e in std::thread::_Invoker<std::tuple<void (learning_dds::DDSPublisher::*)(unsigned int), learning_dds::DDSPublisher*, unsigned int> >::operator() (this=0x6088ac2539d8)
    at /usr/include/c++/11/bits/std_thread.h:266
#26 0x00006088ab870f5e in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (learning_dds::DDSPublisher::*)(unsigned int), learning_dds::DDSPublisher*, unsigned int> > >::_M_run (
    this=0x6088ac2539d0) at /usr/include/c++/11/bits/std_thread.h:211
#27 0x0000763e9aab0253 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
--Type <RET> for more, q to quit, c to continue without paging--
#28 0x0000763e9a83fac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#29 0x0000763e9a8d0a04 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
### FastDDS 与 Iceoryx 集成或比较 #### 实时系统的背景需求 实时系统通常需要低延迟、高吞吐量以及可靠的通信机制来支持分布式应用之间的数据交换。FastDDS 是一种基于 DDS(Data Distribution Service)标准的高性能中间件,而 Iceoryx 则是一种零拷贝共享内存技术,用于实现实时性和高效的进程间通信。 --- #### FastDDS 特性分析 FastDDS 提供了一种灵活的数据分发服务框架,适用于复杂的分布式环境。它通过发布/订阅模式实现异步消息传递,并具备动态发现功能,能够自动检测网络中的参与者[^3]。此外,FastDDS 支持多种 QoS(Quality of Service)策略,允许开发者针对不同的应用场景调整性能参数,例如可靠性、持久化和带宽优化等。 然而,在传统的流处理架构中,单记录更新方法可能面临扩展性瓶颈。尽管可以通过硬件复制或者上游备份缓冲区的方式增强容错能力,但这些方案难以线性扩展到数百节点规模[^1]。 --- #### Iceoryx 技术特点 Iceoryx 主要专注于本地 IPC(Inter-Process Communication),利用共享内存减少不必要的序列化和反序列化开销。其核心优势在于零拷贝设计,这使得数据能够在生产者和消费者之间高效传输而不需额外副本创建。这种特性对于时间敏感型任务尤为重要,因为它显著降低了 CPU 负载并减少了端到端延迟。 另外值得注意的是,Iceoryx 并不局限于特定协议栈,而是作为一个底层基础设施可以与其他高层软件无缝协作。例如,当结合 ROS2 使用时,它可以进一步提升整体效率[^4]。 --- #### FastDDS vs Iceoryx 对比 | **维度** | **FastDDS** | **Iceoryx** | |-------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | **适用场景** | 分布式网络环境下多节点间的可靠通讯 | 同一主机上不同进程间快速交互 | | **通信方式** | 基于 TCP/UDP 协议栈 | 共享内存 | | **延迟能力** | 较好,但仍受网络条件影响 | 极佳,几乎无额外延迟 | | **资源消耗** | 中等到较高 | 很低 | | **开发复杂度** | 相对较高,涉及较多配置 | 简洁直观 | 从上述表格可以看出两者各有侧重:如果目标是构建跨机器的大范围互联生态,则推荐选用 FastDDS;而对于那些追求极致效能且主要活动限定在同一计算平台内部的应用来说,Iceoryx 显然是更优的选择。 --- #### FastDDS 与 Iceoryx 的潜在集成可能性 理论上讲,这两种工具并非互斥关系,反而存在互补空间。设想一下这样的混合架构——在远程连接部分采用 FastDDS 来管理广域网上的信息流动,而在本地则借助 Iceoryx 加速临近组件间的资料分享过程。如此组合既保留了前者强大的互联互通属性,又充分利用后者卓越的速度表现[^5]。 具体实施过程中需要注意如何平滑过渡两种风格迥异的操作逻辑,比如统一命名约定、同步状态机转换规则等等。同时也要考虑到可能出现的新挑战,像安全性考量、错误恢复流程定义等问题都需要提前规划解决办法。 ```cpp // Example Code Snippet Showing Integration Conceptually #include "fastdds/dds/domain/DomainParticipantFactory.hpp" #include "iceoryx_posh/popo/user_trigger.hpp" int main() { eprosima::fastdds::dds::DomainParticipant* participant = eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->create_participant(0); iox::popo::UserTrigger trigger; // Further code would include setting up listeners and handlers... } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值