1. 新建ild文件
新建一个txt文档,命名为:MessageTopic.idl
使用文本工具打开这个文件,输入以下内容后保存
module MessageTopic{
#pragma DCPS_DATA_TYPE "MessageTopic::Msg"
#pragma DCPS_DATA_KEY "MessageTopic::Msg uuid"
struct Msg{
string uuid;
string msgInfo;
};
};
备注:
MessageTopic::Msg:必须和模块名字和结构体的名称一致;
MessageTopic::Msg uuid:uuid必须是结构体中的成员,名字保持一致。
DCPS_DATA_TYPE:idl要求定义的数据类型,而且必须是一个结构体,结构体内部的数据类型可以根据需要自定义。在编译的时候,会自动根据这个宏编译。
DCPS_DATA_KEY:表明了DCPS_DATA_TYPE数据类型的一个键值。键值用来区分同一个主题内的不同实体。在上面的idl定义中:uuid是数据类型MessageTopic::Msg唯一的建,每次发布时都必须是唯一的uuid值,这样可以区分不同的实例。
2. 编译ild文件
通过开始菜单,打开【VS2015开发人员命令提示】
进入到MessageTopic.idl所在的目录。
输入命令:
tao_idl MessageTopic.idl
如果不能运行,则要查看ACE_ROOT、TAO_ROOT、DDS_ROOT的环境变量是否添加上,并且把ACE和DDS的bin和lib目录添加到Path中。
编译完成之后,在对应的目录下面会对应的出现几个文件
然后在使用openDDS编译idl,同样通过输入命令编译:
opendds_idl MessageTopic.idl
编译完成之后,会多生成3个文件:
其中MessageTopicTypeSupport.idl包含了MsgTypeSupport、MsgDataWriter、MsgDataReader的定义。这个定义的接口数据类型会在稍后注册数据类型、发布数据样本和接收数据样本中使用
3. 编辑mpc文件
新建MessageTopic.mpc文件,和idl文件在同一个目录下,把以下内容拷到文件中:
project(*idl): dcps{
TypeSupport_Files{
MessageTopic.idl
}
custom_only = 1
}
在输入命令:
mwc.pl -type vc14
在目录下面就会生成sln文件,使用VS2015打开.sln文件,编译通过!
4. 编写发布端
在原来的mpc文件中添加如下内容,并且在目录下面新建一个Publisher.cpp的空文件。
project(*Publisher) : dcpsexe_with_tcp {
exename = publisher
after += *idl
TypeSupport_Files {
MessageTopic.idl
}
Source_Files {
Publisher.cpp
}
}
添加之后的mpc的内容为:
然后在运行命令行:
mwc.pl -type vc14
重新生成sln文件。打开sln文件编写Publisher.cpp文件的内容;
Publisher.cpp文件中的内容:
#include "MessageTopicTypeSupportImpl.h"
#include <dds/DCPS/Service_Participant.h>
#include <dds/DCPS/Marked_Default_Qos.h>
#include <dds/DCPS/PublisherImpl.h>
#include <dds/DCPS/transport/tcp/TcpInst.h>
#include "dds/DCPS/StaticIncludes.h"
#include <ace/streams.h>
#include "ace/Get_Opt.h"
#include "ace/OS_NS_unistd.h"
int main(int argc, char *argv[]) {
//1.为当前进程初始化一个OpenDDS参与者
/*
调用宏TheParticipantFactoryWithArgs使用命令行初始化参与者工厂,
这个命令行参数用来初始化ORB服务
*/
DDS::DomainParticipantFactory_var dpf = TheParticipantFactoryWithArgs(argc, argv);
/*
在域参与者工厂中注册一个域参与者,使用默认的QoS策略,
指定域ID为42(域ID可以范围0x0-0x7FFFFFFF之间的任意值)
使用DDS默认的状态掩码,确保所有在中间件中的相关通信状态改变都能传递到应用程序中
返回值:域参与对象的引用,用来注册待公布的数据类型
*/
DDS::DomainParticipant_var participant = dpf->create_participant(42
, PARTICIPANT_QOS_DEFAULT
, 0
, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
//2.注册数据类型并创建主题
MessageTopic::MsgTypeSupport_var mts = new MessageTopic::MsgTypeSupportImpl();
/*
调用register_type注册一个带有类型名称的类型
下面代码中:使用空类型名称,DDS缺省会把MsgTypeSupport接口标识符作为该类型的名称,
当然也可以输入“msg”这样的特定类型的名称
*/
if (DDS::RETCODE_OK != mts->register_type(participant, "")) {
return -1;
}
/*
从类型支持对象中获得注册类型名称,调用create_topic来创建主题.
下面创建一个名称为“MsgInfo”的主题,默认主题类型和默认的QoS策略
*/
CORBA::String_var typeName = mts->get_type_name();
DDS::Topic_var topic = participant->create_topic("MsgInfo"
, typeName,
TOPIC_QOS_DEFAULT,
0,
OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!topic){
return -2;
}
//3.创建公布者
/*
创建一个默认公布者QoS策略的公布者
*/
DDS::Publisher_var pub = participant->create_publisher(PUBLISHER_QOS_DEFAULT
,0
,OpenDDS::DCPS::DEFAULT_STATUS_MASK );
if (!pub){
return -3;
}
//4.创建数据写入者
/*
有了公布者,在调用create_datawriter()创建一个数据写入者
使用已经创建好的主题,默认的QoS策略和空的监听者
*/
DDS::DataWriter_var writer = pub->create_datawriter(topic
,DATAWRITER_QOS_DEFAULT
,0
, OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!writer){
return -4;
}
/*
将数据写入者引用转换为MsgDataWriter对象引用,方便使用户数写入者类已经定义好的接口
*/
MessageTopic::MsgDataWriter_var msgWriter = MessageTopic::MsgDataWriter::_narrow(writer);
//5.发布数据
/*
对于每个循环,调用write将数据发送给所有注册过改主题的订阅者
*/
MessageTopic::Msg msg;
msg.uuid = "1";
msg.msgInfo = "qqqqwqefgdafd";
DDS::ReturnCode_t error = msgWriter->write(msg, DDS::HANDLE_NIL);
if (error != DDS::RETCODE_OK){
return -5;
}
//6.等待接收
/*
由于DDS中的数据公布和数据订阅是解耦的,数据发布出去之后,接受者不一定能接收到。
如果发布者要求所有的发布的数据全部被交付,需要在发布端调用调用数据写入者的wait_for_acknowledgements()操作,
来使发布端的应用程序一直等待,处于阻塞状态,直到订阅端接收到所有发布的数据。
要使wait_for_acknowledgements()操作有效,数据读者必须使用QoS策略为RELIABILITY。
QoS策略缺省值为RELIABLE.
数据写入者调用这个函数,并且绑定一个timeout值作为等待的超时时间。
*/
DDS::Duration_t shutdownDelay = { 15,0 };
DDS::ReturnCode_t result = writer->wait_for_acknowledgments(shutdownDelay);
if (result != DDS::RETCODE_OK){
return -6;
}
//7.实体清理
/*
在公布完数据以后,需要清理与OpenDDS相关的资源
*/
participant->delete_contained_entities();
dpf->delete_participant(participant);
TheServiceParticipant->shutdown();
return 0;
}
6. 编写订阅端
同样和发布端一样,在mpc文件中,添加如下内容:
project(*Subscriber) : dcpsexe_with_tcp {
exename = subscriber
after += *idl
TypeSupport_Files {
MessageTopic.idl
}
Source_Files {
Subscriber.cpp
DataReaderListenerImpl.cpp
}
}
添加之后的mpc文件:
和编译发布端一样,同样使用【VS2015开发者工具】命令窗口,输入以下命令:
mwc.pl -type vc14
并且在目录下面新建三个空文件:Subscriber.cpp、DataReaderListenerImpl.h、DataReaderListenerImpl.cpp,分别用来编写订阅端的逻辑代码,并且把这三个文件添加到项目中。
Subscriber.cpp的源码
#include "MessageTopicTypeSupportImpl.h"
#include <dds/DCPS/Service_Participant.h>
#include <dds/DCPS/Marked_Default_Qos.h>
#include <dds/DCPS/PublisherImpl.h>
#include <dds/DCPS/transport/tcp/TcpInst.h>
#include "dds/DCPS/StaticIncludes.h"
#include <ace/streams.h>
#include "ace/Get_Opt.h"
#include "ace/OS_NS_unistd.h"
#include "DataReaderListenerImpl.h"
using namespace MessageTopic;
int main(int argc, char *argv[]) {
//1.初始化参与者
DDS::DomainParticipantFactory_var dpf = TheParticipantFactoryWithArgs(argc, argv);
DDS::DomainParticipant_var participant = dpf->create_participant(42//域ID
,PARTICIPANT_QOS_DEFAULT
,0
,OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!participant){
return -1;
}
//2.注册数据类型并创建主题
MessageTopic::MsgTypeSupport_var mts = new MessageTopic::MsgTypeSupportImpl();
if (DDS::RETCODE_OK != mts->register_type(participant, "")){
return -20;
}
CORBA::String_var typeName = mts->get_type_name();
DDS::Topic_var topic = participant->create_topic("MsgInfo"
,typeName
,TOPIC_QOS_DEFAULT
,0
,OpenDDS::DCPS::DEFAULT_STATUS_MASK
);
if (!topic){
return -21;
}
//3.创建订阅者
/*
调用create_subscriber()操作创建一个带有默认QoS策略的订阅者
*/
DDS::Subscriber_var sub = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT
,0
,OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!sub){
return -3;
}
//4.创建数据读者以及监听者
/*
订阅端需要给数据读者关联一个监听者,用来接收数据的到达
*/
DDS::DataReaderListener_var listener(new DataReaderListenerImpl);
/*
采用默认的QoS策略创建读者,并将它与主题、刚刚创建的监听者对象相关联起来
创建完成之后,主线程就可以去处理其他工作了。
当有数据到达时,OpenDDS会调用监听者对象的回调接口通知,在DataReaderListenerImpl类的回调函数中接收需要的数据就可多了
*/
DDS::DataReader_var dr = sub->create_datareader(topic
,DATAREADER_QOS_DEFAULT
,listener
,OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!dr){
return -4;
}
while (1) {
ACE_OS::sleep(1);
}
//5.清理实体
/*
在订阅完数据以后,需要清理与OpenDDS相关联的资源
delete_contained_entities删除所有该参与者创建的主题、订阅者
*/
participant->delete_contained_entities();
dpf->delete_participant(participant);
TheServiceParticipant->shutdown();
return 0;
}
DataReaderListenerImpl.h
// -*- C++ -*-
//
#ifndef DATAREADER_LISTENER_IMPL
#define DATAREADER_LISTENER_IMPL
#include <dds/DdsDcpsSubscriptionExtC.h>
#include <dds/DCPS/LocalObject.h>
#if !defined (ACE_LACKS_PRAGMA_ONCE)
#pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
class DataReaderListenerImpl
: public virtual OpenDDS::DCPS::LocalObject<OpenDDS::DCPS::DataReaderListener> {
public:
DataReaderListenerImpl();
virtual ~DataReaderListenerImpl(void);
virtual void on_requested_deadline_missed(
DDS::DataReader_ptr reader,
const DDS::RequestedDeadlineMissedStatus & status);
virtual void on_requested_incompatible_qos(
DDS::DataReader_ptr reader,
const DDS::RequestedIncompatibleQosStatus & status);
virtual void on_liveliness_changed(
DDS::DataReader_ptr reader,
const DDS::LivelinessChangedStatus & status);
virtual void on_subscription_matched(
DDS::DataReader_ptr reader,
const DDS::SubscriptionMatchedStatus & status);
virtual void on_sample_rejected(
DDS::DataReader_ptr reader,
const DDS::SampleRejectedStatus& status);
virtual void on_data_available(
DDS::DataReader_ptr reader);
virtual void on_sample_lost(
DDS::DataReader_ptr reader,
const DDS::SampleLostStatus& status);
virtual void on_subscription_disconnected(
DDS::DataReader_ptr reader,
const ::OpenDDS::DCPS::SubscriptionDisconnectedStatus & status);
virtual void on_subscription_reconnected(
DDS::DataReader_ptr reader,
const ::OpenDDS::DCPS::SubscriptionReconnectedStatus & status);
virtual void on_subscription_lost(
DDS::DataReader_ptr reader,
const ::OpenDDS::DCPS::SubscriptionLostStatus & status);
virtual void on_connection_deleted(
::DDS::DataReader_ptr reader);
virtual void on_budget_exceeded(
DDS::DataReader_ptr reader,
const ::OpenDDS::DCPS::BudgetExceededStatus& status);
long num_reads() const {
return num_reads_;
}
private:
DDS::DataReader_var reader_;
long num_reads_;
};
#endif /* DATAREADER_LISTENER_IMPL */
DataReaderListenerImpl.cpp
// -*- C++ -*-
//
#include "DataReaderListenerImpl.h"
#include "MessageTopicTypeSupportC.h"
#include "MessageTopicTypeSupportImpl.h"
#include <dds/DCPS/Service_Participant.h>
#include <ace/streams.h>
using namespace MessageTopic;
DataReaderListenerImpl::DataReaderListenerImpl()
: num_reads_(0) {
}
DataReaderListenerImpl::~DataReaderListenerImpl() {
}
void DataReaderListenerImpl::on_data_available(DDS::DataReader_ptr reader) {
++num_reads_;
try {
MessageTopic::MsgDataReader_var message_dr = MessageTopic::MsgDataReader::_narrow(reader);
if (CORBA::is_nil(message_dr.in())) {
cerr << "read: _narrow failed." << endl;
exit(1);
}
MessageTopic::Msg message;
DDS::SampleInfo si;
DDS::ReturnCode_t status = message_dr->take_next_sample(message, si);
if (status == DDS::RETCODE_OK) {
cout << "Message: is = " << message.uuid << endl
<< " msgInfo = " << message.msgInfo << endl;
cout << "SampleInfo.sample_rank = " << si.sample_rank << endl;
} else if (status == DDS::RETCODE_NO_DATA) {
cerr << "ERROR: reader received DDS::RETCODE_NO_DATA!" << endl;
} else {
cerr << "ERROR: read Message: Error: " << status << endl;
}
} catch (CORBA::Exception& e) {
cerr << "Exception caught in read:" << endl << e << endl;
exit(1);
}
}
void DataReaderListenerImpl::on_requested_deadline_missed(
DDS::DataReader_ptr,
const DDS::RequestedDeadlineMissedStatus &) {
cerr << "DataReaderListenerImpl::on_requested_deadline_missed" << endl;
}
void DataReaderListenerImpl::on_requested_incompatible_qos(
DDS::DataReader_ptr,
const DDS::RequestedIncompatibleQosStatus &) {
cerr << "DataReaderListenerImpl::on_requested_incompatible_qos" << endl;
}
void DataReaderListenerImpl::on_liveliness_changed(
DDS::DataReader_ptr,
const DDS::LivelinessChangedStatus &) {
cerr << "DataReaderListenerImpl::on_liveliness_changed" << endl;
}
void DataReaderListenerImpl::on_subscription_matched(
DDS::DataReader_ptr,
const DDS::SubscriptionMatchedStatus &) {
cerr << "DataReaderListenerImpl::on_subscription_matched" << endl;
}
void DataReaderListenerImpl::on_sample_rejected(
DDS::DataReader_ptr,
const DDS::SampleRejectedStatus&) {
cerr << "DataReaderListenerImpl::on_sample_rejected" << endl;
}
void DataReaderListenerImpl::on_sample_lost(
DDS::DataReader_ptr,
const DDS::SampleLostStatus&) {
cerr << "DataReaderListenerImpl::on_sample_lost" << endl;
}
void DataReaderListenerImpl::on_subscription_disconnected(
DDS::DataReader_ptr,
const ::OpenDDS::DCPS::SubscriptionDisconnectedStatus &) {
cerr << "DataReaderListenerImpl::on_subscription_disconnected" << endl;
}
void DataReaderListenerImpl::on_subscription_reconnected(
DDS::DataReader_ptr,
const ::OpenDDS::DCPS::SubscriptionReconnectedStatus &) {
cerr << "DataReaderListenerImpl::on_subscription_reconnected" << endl;
}
void DataReaderListenerImpl::on_subscription_lost(
DDS::DataReader_ptr,
const ::OpenDDS::DCPS::SubscriptionLostStatus &) {
cerr << "DataReaderListenerImpl::on_subscription_lost" << endl;
}
void DataReaderListenerImpl::on_budget_exceeded(
DDS::DataReader_ptr,
const ::OpenDDS::DCPS::BudgetExceededStatus&) {
cerr << "DataReaderListenerImpl::on_budget_exceeded" << endl;
}
void DataReaderListenerImpl::on_connection_deleted(::DDS::DataReader_ptr reader) {
}
7. 生成exe
编译整个项目,在根目录下生成exe
aaa