3. 配置RTPS发现协议
任务说明
在OpenDDS中,默认使用RTPS(Real-Time Publish-Subscribe)发现协议实现参与者之间的自动发现。本案例将配置两个独立进程(发布端与订阅端),使其通过RTPS发现协议在不同主机或同一主机的不同端口上相互发现并完成通信。
环境依赖
需要OpenDDS 3.x(含内置RTPS支持)及ACE/TAO。编译前确认DDS_ROOT与ACE_ROOT环境变量已正确设置。
实现代码
以下为完整的发布端与订阅端实现,使用RTPS发现协议(默认配置即启用,无需额外参数)。代码中显式配置了Discovery的kind为RTPS,并设置监听端口为7400,确保不同主机可通过该端口互相发现。
// Publisher.cpp
#include <iostream>
#include <string>
#include "dds/DCPS/Service_Participant.h"
#include "dds/DCPS/Marked_Default_Qos.h"
#include "dds/DCPS/PublisherImpl.h"
#include "dds/DCPS/SubscriberImpl.h"
#include "dds/DCPS/transport/framework/TransportRegistry.h"
#include "dds/DCPS/transport/rtps_udp/RtpsUdp.h"
#include "dds/DCPS/RTPS/RtpsDiscovery.h"
#include "MessengerTypeSupportImpl.h"
int main(int argc, char* argv[]) {
// 初始化参与者,使用RTPS发现
TheServiceParticipant->set_discovery("RTPS", new OpenDDS::RTPS::RtpsDiscovery("RTPS"));
DDS::DomainParticipantFactory_var dpf = TheParticipantFactoryWithArgs(argc, argv);
DDS::DomainParticipant_var participant = dpf->create_participant(
42, PARTICIPANT_QOS_DEFAULT, 0, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!participant) { std::cerr << "Participant creation failed\n"; return 1; }
// 注册类型
Messenger::MessageTypeSupport_var ts = new Messenger::MessageTypeSupportImpl();
if (ts->register_type(participant, "") != DDS::RETCODE_OK) return 1;
// 创建发布者与数据写入者
DDS::Publisher_var pub = participant->create_publisher(PUBLISHER_QOS_DEFAULT, 0, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
DDS::DataWriter_var dw = pub->create_datawriter(ts->get_type_name(), DATAWRITER_QOS_DEFAULT, 0, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
Messenger::MessageDataWriter_var writer = Messenger::MessageDataWriter::_narrow(dw);
// 发送10条消息
for (int i = 0; i < 10; ++i) {
Messenger::Message msg;
msg.subject = "RTPS Discovery Test";
msg.text = "Message " + std::to_string(i);
msg.count = i;
writer->write(msg, DDS::HANDLE_NIL);
std::cout << "Sent: " << msg.text << std::endl;
ACE_OS::sleep(1);
}
return 0;
}
// Subscriber.cpp
#include <iostream>
#include "dds/DCPS/Service_Participant.h"
#include "dds/DCPS/Marked_Default_Qos.h"
#include "dds/DCPS/PublisherImpl.h"
#include "dds/DCPS/SubscriberImpl.h"
#include "dds/DCPS/transport/framework/TransportRegistry.h"
#include "dds/DCPS/transport/rtps_udp/RtpsUdp.h"
#include "dds/DCPS/RTPS/RtpsDiscovery.h"
#include "MessengerTypeSupportImpl.h"
class Listener : public DDS::DataReaderListener {
public:
void on_data_available(DDS::DataReader_ptr reader) override {
Messenger::MessageDataReader_var dr = Messenger::MessageDataReader::_narrow(reader);
Messenger::Message msg;
DDS::SampleInfo si;
while (dr->take_next_sample(msg, si) == DDS::RETCODE_OK) {
if (si.valid_data) {
std::cout << "Received: " << msg.text << std::endl;
}
}
}
};
int main(int argc, char* argv[]) {
TheServiceParticipant->set_discovery("RTPS", new OpenDDS::RTPS::RtpsDiscovery("RTPS"));
DDS::DomainParticipantFactory_var dpf = TheParticipantFactoryWithArgs(argc, argv);
DDS::DomainParticipant_var participant = dpf->create_participant(
42, PARTICIPANT_QOS_DEFAULT, 0, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!participant) { std::cerr << "Participant creation failed\n"; return 1; }
Messenger::MessageTypeSupport_var ts = new Messenger::MessageTypeSupportImpl();
if (ts->register_type(participant, "") != DDS::RETCODE_OK) return 1;
DDS::Subscriber_var sub = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT, 0, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
DDS::DataReader_var dr = sub->create_datareader(ts->get_type_name(), DATAREADER_QOS_DEFAULT, new Listener, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
std::cout << "Subscriber waiting for messages..." << std::endl;
ACE_OS::sleep(15);
return 0;
}
编译与运行
使用MPC生成构建文件后编译(需包含Messenger.idl生成的类型支持代码):
# 在项目目录下
$ACE_ROOT/bin/mwc.pl -type gnuace
make
# 终端1(发布端)
./publisher -DCPSConfigFile rtps.ini
# 终端2(订阅端,可运行于另一主机)
./subscriber -DCPSConfigFile rtps.ini
rtps.ini配置文件内容:
[common]
DCPSGlobalTransportConfig=rtps
[transport_rtps]
transport_type=rtps_udp
local_address=0.0.0.0:7400
验证方法
启动订阅端后,再启动发布端。若RTPS发现成功,订阅端控制台会依次打印Received: Message 0至Message 9。若未收到消息,检查两端7400端口UDP连通性(如netstat -an | grep 7400),并确认防火墙允许该端口通信。
常见问题
- 发现失败:确认两端使用相同Domain ID(本例为42),且
rtps.ini中端口一致。 - 跨网段通信:RTPS默认使用组播,若网络禁组播,可在配置中指定对端单播地址(
use_multicast=0并添加unicast_address)。