【DDS】基于OpenDDS的DDS-RPC实现

本文介绍如何基于OpenDDS实现DDS-RPC通信机制。DDS为数据分布服务,RPC为远程过程调用,结合两者可实现实时分布式系统中服务的远程调用。文章详细解释了IDL定义、主题文件生成、Publisher/Subscriber配置、DataWriter/DataReader使用及本地实现流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于OpenDDS的DDS-RPC实现

DDS-RPC:

  • DDS指Data Distribution Service,是OMG(Object Management Group)提出的规范。DDS类似于总线的概念,用于数据交互。
  • RPC指Remote Procedure Calls,远过程调用。比方说,远程服务端提供一个了方法,客户端可以调用这个方法。

既然,DDS可以进行数据交互,那么理论上基于DDS便可以实现RPC机制。

DDS-RPC实现

OpenDDS没有实现RPC,但根据RPC over DDS给出的规范。可以利用OpenDDS实现 DDS-RPC。在实现上,主要包括以下几个部分:

  • IDL定义
    根据DDS-RPC规范,定义OpenDDS可以识别的IDL文件(主题)。

  • 主题文件生成
    根据上一步,定义的IDL文件,利用OpenDDS提供的工具生成主体文件(.h/.cpp)

  • Publisher/Subscribe
    服务端和客户端,相当于两个Participation。每个Participation需要包含一个P端,一个S端。

  • DataWriter/DataReader。
    DateWriter负责写入请求数据,DataReader负责读取订阅的数据。

  • 本地实现
    当服务器端的DataReader接收到请求端的数据时,根据调用的方法,调用具体的本地实现。方法调用后,将返回值通过DataWriter告知客户端。
    当客户端的DataReader接收到数据后,调用相应的本地实现,告知其返回结果。

  • 代码源码GitHub地址如下:
    https://github.com/adver1991/DDS-Example/tree/dds-rpc

  • IDL文件示例

#ifdef INTERFACE
module robot {

@DDSService
interface RobotControl 
{
  float setSpeed(float speed);
  float getSpeed();
};

}; //module robot
#endif // INTERFACE

#ifndef MY_BASIC
#define MY_BASIC

#include <rpc_types.idl>

module robot {

/***********************************************/
/*                   Request Types             */
/***********************************************/
@nested
struct RobotControl_setSpeed_In 
{
    float speed;
};

@nested
struct RobotControl_getSpeed_In 
{ 
  DDS::RPC::UnusedMember dummy; 
};

const long RobotControl_setSpeed_Hash  = 1;
const long RobotControl_getSpeed_Hash  = 2;

@nested
union RobotControl_Call switch(long) 
{
    default:
       DDS::RPC::UnknownOperation unknownOp;

    case RobotControl_setSpeed_Hash:
       RobotControl_setSpeed_In setSpeed;

    case RobotControl_getSpeed_Hash:
       RobotControl_getSpeed_In getSpeed;
};

@topic
struct RobotControl_Request 
{
  DDS::RPC::RequestHeader header;
  RobotControl_Call       data;
};

/***********************************************/
/*                   Reply Types               */
/***********************************************/
@nested
struct RobotControl_setSpeed_Out 
{
  float return_;
};

@nested
struct RobotControl_getSpeed_Out 
{ 
  float return_; 
};

@nested
union RobotControl_setSpeed_Result switch(DDS::RPC::RemoteExceptionCode_t)
{
  default:
    DDS::RPC::UnknownException unknownEx;

  case DDS::RPC::REMOTE_EX_OK:
    RobotControl_setSpeed_Out result;
};

@nested
union RobotControl_getSpeed_Result switch(DDS::RPC::RemoteExceptionCode_t)
{
  default:
    DDS::RPC::UnknownException unknownEx;
  
  case DDS::RPC::REMOTE_EX_OK:
    RobotControl_getSpeed_Out result;
};

@nested
union RobotControl_Return switch(long)
{
  default: 
    DDS::RPC::UnknownOperation unknownOp;

  case RobotControl_setSpeed_Hash:
    RobotControl_setSpeed_Result setSpeed;

  case RobotControl_getSpeed_Hash:
    RobotControl_getSpeed_Result getSpeed;
};

@topic
struct RobotControl_Reply
{
  DDS::RPC::ReplyHeader  header;
  RobotControl_Return    data;
};

}; // module robot
#endif /* MY_BASIC */
DDS系列

【DDS】DDS与OpenDDS
【DDS】DDS-RPC通信机制
【DDS】基于OpenDDS的DDS-RPC实现
【DDS】DDSI-RTPS规范

04-21
### DDSRPC集成的技术分析 #### 1. DDS作为中间件支持远程过程调用(RPCDDS本身是一种高性能、实时分布式数据分发协议,主要关注于基于主题的消息传递机制。然而,在某些场景下,开发者可能希望利用DDS实现远程过程调用(RPC)。这可以通过将DDS的功能扩展到支持请求/响应模式来完成[^2]。 为了实现这一目标,通常的做法是定义一对特定的主题:一个是用于发送请求消息的主题,另一个则是接收响应消息的主题。客户端会向服务端发布带有参数的请求消息;而服务器则监听这些请求并返回结果给相应的客户端。这种设计允许在保持DDS核心优势的同时引入类似于传统RPC的行为。 #### 2. 使用IDL桥接ROS MSG与DDS 当考虑如何让现有的机器人操作系统(ROS)能够运行在DDS之上时,一个重要方面就是能否无缝转换两者之间的消息格式。具体来说,这意味着要解决从ROS自定义MSG文件生成兼容DDS标准接口描述语言(IDL)表示形式的问题[^1]。一旦成功实现了这一点,则不仅简化了跨平台移植工作量,而且也为构建更复杂的系统奠定了基础——比如那些既依赖传感器融合又需要执行复杂计算任务的应用场合。 此外值得注意的是,虽然理论上存在多种方法可以达成上述目的,但在实际操作过程中可能会遇到不少挑战。例如,不同厂商所提供的DDS库之间可能存在细微差异,从而影响最终程序行为的一致性和可移植性程度。因此建议开发人员仔细评估所选解决方案的具体需求后再做决定。 #### 3. 配置难度考量 配置DDS环境相对较为复杂,因为它涉及到多个层面设置选项调整以及网络拓扑结构规划等方面的知识点。对于初学者而言,理解整个框架的工作原理及其内部工作机制并非易事。不过随着经验积累和技术文档学习深入,大多数常见问题都可以得到有效处理。 以下是采用Python伪代码展示的一个简单例子,演示了如何通过DDS创建基本的服务-客户关系: ```python import dds class RequestType: pass # Define your request structure here. class ResponseType: pass # Define your response structure here. request_topic = dds.Topic("RequestTopic", RequestType) response_topic = dds.Topic("ResponseTopic", ResponseType) def client(): writer = dds.DataWriter(request_topic) reader = dds.DataReader(response_topic) req = RequestType() # Populate 'req' fields... writer.write(req) while True: resp = reader.take_next_sample() if resp.valid_data: break return resp.data def server(): writer = dds.DataWriter(response_topic) reader = dds.DataReader(request_topic) while True: req = reader.take_next_sample().data res = process_request(req) # Implement this function. writer.write(res) ``` 此示例展示了如何建立一个简单的双向通信链路,其中一方充当发起者角色发出询问,另一方负责回应解答。当然实际情况往往更加错综复杂,还需要考虑到错误恢复策略等因素的影响。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值