基于OpenDDS的应用开发(Linux),大体和Windows平台类似,也分两个部分的工作:
(1)定义自己的IDL文件,并编译成传输数据类型通讯动态库.so文件;
(2)分别编写pub和sub程序,运行
具体步骤,有以下几个:
定义idl文件,如HelloMsg.ild
运行脚本,产生相应的消息类型符号导出头文件HelloMsgCommon_Export.h
编写mwc、mpc工作台和项目文件,如HelloMsg.mwc、HelloMsg.mpc
编写HelloMsgPub.cpp和HelloMsgSub.cpp代码;
执行make编译,产生动态库libHelloMsgCommon.so、HelloMsgPub、HelloMsgSub
运行发布和订阅程序,查看运行结果
步骤一、定义HelloMsg.idl
module Hello
{
#pragma DCPS_DATA_TYPE "Hello::HelloMsg"
#pragma DCPS_DATA_KEY "Hello::HelloMsg msg"
struct HelloMsg{
string msg;
};
};
步骤二、制作HelloMsg消息导出符号头文件HelloMsgCommon_Export.h
perl %ACE_ROOT%/bin/generate_export_file.pl HelloMsgCommon > HelloMsgCommon_Export.h
步骤三、定义HelloMsg.mwc、HelloMsg.mpc
workspace {
// the -relative and -include cmdlines make it so this workspace
// does not have to be in the $DDS_ROOT directory tree.
// tell MPC to substitute our DDS_ROOT environment variables for relative paths
cmdline += -relative DDS_ROOT=$DDS_ROOT
// tell the projects where to find the DDS base projects (*.mpb)
cmdline += -include $DDS_ROOT/MPC/config
}
project(*Common) : dcps {
sharedname = HelloMsgCommon
dynamicflags = HELLOMSGCOMMON_BUILD_DLL
libout = .
requires += tao_orbsvcs
requires += no_opendds_safety_profile
after += Svc_Utils
includes += $(TAO_ROOT)/orbsvcs
idlflags += -I$(TAO_ROOT)/orbsvcs \
-Wb,export_macro=HelloMsgCommon_Export \
-Wb,export_include=HelloMsgCommon_Export.h
dcps_ts_flags += -Wb,export_macro=HelloMsgCommon_Export
TypeSupport_Files {
HelloMsg.idl
}
IDL_Files {
HelloMsgTypeSupport.idl
HelloMsg.idl
}
// We only want the generated files
Header_Files {
}
// We only want the generated files
Source_Files {
}
}
project(HelloMsgPub) : dcpsexe, dcps_tcp, svc_utils {
after += *Common
exename = HelloMsgPub
requires += tao_orbsvcs
requires += no_opendds_safety_profile
includes += $(TAO_ROOT)/orbsvcs
libs += HelloMsgCommon
IDL_Files {
}
TypeSupport_Files {
}
Header_Files {
}
Source_Files {
HelloMsgPub.cpp
}
Documentation_Files {
dds_tcp_conf.ini
dds_udp_conf.ini
}
}
project(HelloMsgSub) : dcpsexe, dcps_tcp {
after += *Common
exename = HelloMsgSub
requires += tao_orbsvcs
requires += no_opendds_safety_profile
includes += $(TAO_ROOT)/orbsvcs
libs += HelloMsgCommon
TypeSupport_Files {
}
IDL_Files {
}
Header_Files {
}
Source_Files {
HelloMsgSub.cpp
}
Documentation_Files {
dds_tcp_conf.ini
dds_udp_conf.ini
}
}
步骤五、编写HelloMsgPub.cpp和HelloMsgSub.cpp代码
HelloMsgPub.cpp
/****************************************************************
*
* file: HelloMsgPub.cpp
* desc: Provides a simple C++ 'hello world' DDS publisher.
* This publishing application will send data
* to the example 'hello world' subscribing
* application (hello_sub).
*
****************************************************************/
#include <dds/DCPS/Service_Participant.h>
#include <dds/DCPS/Marked_Default_Qos.h>
#include <dds/DCPS/PublisherImpl.h>
#include "dds/DCPS/StaticIncludes.h"
#include <ace/streams.h>
#include <orbsvcs/Time_Utilities.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "HelloMsgTypeSupportImpl.h"
/****************************************************************
* main()
*
* Perform OpenDDS setup activities:
* - create a Domain Participant
* - create a Publisher
* - register the StringMsg data type
* - create a Topic
* - create a DataWriter
* Write data
****************************************************************/
int main(int argc, char * argv[])
{
DDS::DomainParticipant * domain;
DDS::Publisher * publisher;
DDS::Topic * topic;
DDS::DataWriter * dw;
Hello::StringMsg stringMsg;
DDS::ReturnCode_t retval;
DDS::DomainParticipantFactory *dpf =
TheParticipantFactoryWithArgs(argc, argv);
if ( dpf == NULL )
{
printf("ERROR initializing domainParticipantFactory.\n");
return -1;
}
/* create a DomainParticipant */
domain = dpf->create_participant( 2,
PARTICIPANT_QOS_DEFAULT,
NULL,
0 );
if ( domain == NULL )
{
printf("ERROR creating domain participant.\n");
return -1;
}
/* create a Publisher */
publisher = domain->create_publisher(PUBLISHER_QOS_DEFAULT,
NULL,
0 );
if ( publisher == NULL )
{
printf("ERROR creating publisher.\n");
return -1;
}
/* Register the data type with the OpenDDS middleware.
* This is required before creating a Topic with
* this data type.
*/
Hello::StringMsgTypeSupport *stringMsgTS = new Hello::StringMsgTypeSupportImpl();;
retval = stringMsgTS->register_type( domain, "StringMsg" );
if (retval != DDS::RETCODE_OK)
{
printf("ERROR registering type: %s\n", "DDS_error(retval)");
return -1;
}
/* Create a DDS Topic with the StringMsg data type. */
topic = domain->create_topic("helloTopic",
"StringMsg",
TOPIC_QOS_DEFAULT,
NULL,
0 );
if ( topic == NULL )
{
printf("ERROR creating topic.\n");
return -1;
}
/* Create a DataWriter on the hello topic, with
* default QoS settings and no listeners.
*/
dw = publisher->create_datawriter( topic,
DATAWRITER_QOS_DEFAULT,
NULL,
0 );
if (dw == NULL)
{
printf("ERROR creating data writer\n");
return -1;
}
/* Initialize the data to send. The StringMsg data type
* has just one string member.
* Note: Alwyas initialize a string member with
* allocated memory -- the destructor will free
* all string members.
*/
stringMsg.msg = new char[1024];
strcpy((char*)stringMsg.msg.in(), "Hello World from C++!");
int counter = 1;
Hello::StringMsgDataWriter* sm_dw = Hello::StringMsgDataWriter::_narrow(dw);
while ( 1 )
{
sprintf((char*)stringMsg.msg.in(), "Hello World from OpenDDS C++! index=%d", counter);
DDS::ReturnCode_t ret = sm_dw->write ( stringMsg, DDS::HANDLE_NIL );
printf("OpenDDS wrote a sample, index=%d\n", counter);
fflush(stdout);
if ( ret != DDS::RETCODE_OK)
{
printf("ERROR writing sample\n");
return -1;
}
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
counter++;
}
/* Cleanup */
retval = domain -> delete_contained_entities();
if ( retval != DDS::RETCODE_OK )
printf("ERROR (%s): Unable to cleanup DDS entities\n",
"DDS_error(retval)");
dpf->delete_participant(domain);
TheServiceParticipant->shutdown();
return 0;
}
HelloMsgSub.cpp
/****************************************************************
*
* file: HelloMsgSub.cpp
* desc: Provides a simple C++ 'Hello World' DDS subscriber.
* This subscribing application will receive data
* from the example 'hello world' publishing
* application (hello_pub).
*
****************************************************************/
#include <dds/DCPS/Service_Participant.h>
#include <dds/DCPS/Marked_Default_Qos.h>
#include <dds/DCPS/PublisherImpl.h>
#include <ace/streams.h>
#include <orbsvcs/Time_Utilities.h>
#include "dds/DCPS/StaticIncludes.h"
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "HelloMsgTypeSupportImpl.h"
#ifdef _WIN32
# define SLEEP(a) Sleep(a*1000)
#else
# define SLEEP(a) sleep(a);
#endif
int all_done = 0;
/****************************************************************
* Construct a DataReaderListener and override the
* on_data_available() method with our own. All other
* listener methods will be default (no-op) functions.
****************************************************************/
class SubListener : public DDS::DataReaderListener
{
public:
void on_data_available( DDS::DataReader * dr );
void on_requested_deadline_missed (
DDS::DataReader_ptr reader,
const DDS::RequestedDeadlineMissedStatus & status);
void on_requested_incompatible_qos (
DDS::DataReader_ptr reader,
const DDS::RequestedIncompatibleQosStatus & status);
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
);
void on_sample_rejected(
DDS::DataReader_ptr reader,
const DDS::SampleRejectedStatus& status
);
void on_sample_lost(
DDS::DataReader_ptr reader,
const DDS::SampleLostStatus& status
);
};
/****************************************************************
* DataReader Listener Method: on_data_avail()
*
* This listener method is called when data is available to
* be read on this DataReader.
****************************************************************/
void SubListener::on_data_available( DDS::DataReader * dr)
{
Hello::StringMsgSeq samples;
DDS::SampleInfoSeq samples_info;
DDS::ReturnCode_t retval;
DDS::SampleStateMask ss = DDS::ANY_SAMPLE_STATE;
DDS::ViewStateMask vs = DDS::ANY_VIEW_STATE;
DDS::InstanceStateMask is = DDS::ANY_INSTANCE_STATE;
/* Convert to our type-specific DataReader */
Hello::StringMsgDataReader* reader = Hello::StringMsgDataReader::_narrow( dr );
/* Take any and all available samples. The take() operation
* will remove the samples from the DataReader so they
* won't be available on subsequent read() or take() calls.
*/
retval = reader->take( samples, samples_info,
DDS::LENGTH_UNLIMITED,
ss,
vs,
is );
if ( retval == DDS::RETCODE_OK )
{
/* iterrate through the samples */
for ( unsigned int i = 0;i < samples.length(); i++)
{
/* If this sample does not contain valid data,
* it is a dispose or other non-data command,
* and, accessing any member from this sample
* would be invalid.
*/
if ( samples_info[i].valid_data)
printf("OpenDDS received a sample, No=%d/%d, [%s]\n", i, samples.length(),
samples[i].msg.in());
}
fflush(stdout);
/* read() and take() always "loan" the data, we need to
* return it so OpenDDS can release resources associated
* with it.
*/
reader->return_loan( samples, samples_info );
}
else
{
printf("ERROR (%s) taking samples from DataReader\n",
"DDS_error(retval)");
}
}
void SubListener::on_requested_deadline_missed (
DDS::DataReader_ptr reader,
const DDS::RequestedDeadlineMissedStatus & status)
{
printf("ERROR (%s) on_requested_deadline_missed\n",
"DDS_error(retval)");
}
void SubListener::on_requested_incompatible_qos (
DDS::DataReader_ptr reader,
const DDS::RequestedIncompatibleQosStatus & status)
{
printf("ERROR (%s) on_requested_incompatible_qos\n",
"DDS_error(retval)");
}
void SubListener::on_liveliness_changed (
DDS::DataReader_ptr reader,
const DDS::LivelinessChangedStatus & status)
{
printf("ERROR (%s) on_liveliness_changed\n",
"DDS_error(retval)");
}
void SubListener::on_subscription_matched (
DDS::DataReader_ptr reader,
const DDS::SubscriptionMatchedStatus & status
)
{
printf("ERROR (%s) on_subscription_matched\n",
"DDS_error(retval)");
}
void SubListener::on_sample_rejected(
DDS::DataReader_ptr reader,
const DDS::SampleRejectedStatus& status
)
{
printf("ERROR (%s) on_sample_rejected\n",
"DDS_error(retval)");
}
void SubListener::on_sample_lost(
DDS::DataReader_ptr reader,
const DDS::SampleLostStatus& status
)
{
printf("ERROR (%s) on_sample_lost\n",
"DDS_error(retval)");
}
/****************************************************************
* main()
*
* Perform OpenDDS setup activities:
* - create a Domain Participant
* - create a Subscriber
* - register the StringMsg data type
* - create a Topic
* - create a DataReader and attach the listener created above
* And wait for data
****************************************************************/
#if defined(__vxworks) && !defined(__RTP__)
int hello_sub(char * args)
#else
int main(int argc, char * argv[])
#endif
{
DDS::DomainParticipant * domain;
DDS::Subscriber * subscriber;
DDS::Topic * topic;
DDS::DataReader * dr;
SubListener drListener;
DDS::ReturnCode_t retval;
/* Get an instance of the DDS DomainPartiticpantFactory --
* we will use this to create a DomainParticipant.
*/
DDS::DomainParticipantFactory *dpf =
TheParticipantFactoryWithArgs(argc, argv);
if ( dpf == NULL )
{
printf("ERROR initializing domainParticipantFactory.\n");
return -1;
}
/* create a DomainParticipant */
domain =
dpf->create_participant( 2,
PARTICIPANT_QOS_DEFAULT,
NULL,
0 );
if ( domain == NULL )
{
printf("ERROR creating domain participant.\n");
return -1;
}
/* create a Subscriber */
subscriber = domain->create_subscriber(SUBSCRIBER_QOS_DEFAULT,
NULL,
0 );
if ( subscriber == NULL )
{
printf("ERROR creating subscriber\n");
return -1;
}
/* Register the data type with the OpenDDS middleware.
* This is required before creating a Topic with
* this data type.
*/
Hello::StringMsgTypeSupport *stringMsgTS = new Hello::StringMsgTypeSupportImpl();;
retval = stringMsgTS->register_type( domain, "StringMsg" );
if (retval != DDS::RETCODE_OK)
{
printf("ERROR registering type: %s\n", "DDS_error(retval)");
return -1;
}
/* create a DDS Topic with the StringMsg data type. */
topic = domain->create_topic( "helloTopic",
"StringMsg",
TOPIC_QOS_DEFAULT,
NULL,
0 );
if ( ! topic )
{
printf("ERROR creating topic\n");
return -1;
}
/* create a DDS_DataReader on the hello topic (notice
* the TopicDescription is used) with default QoS settings,
* and attach our listener with our on_data_available method.
*/
dr = subscriber->create_datareader( (DDS::TopicDescription*)topic,
DATAREADER_QOS_DEFAULT,
&drListener,
DDS::DATA_AVAILABLE_STATUS );
if ( ! dr )
{
printf("ERROR creating data reader\n");
return -1;
}
/* Wait forever. When data arrives at our DataReader,
* our dr_on_data_avilalbe method will be invoked.
*/
while ( !all_done )
SLEEP(30);
/* Cleanup */
retval = domain -> delete_contained_entities();
if ( retval != DDS::RETCODE_OK )
printf("ERROR (%s): Unable to cleanup DDS entities\n",
"DDS_error(retval)");
dpf->delete_participant(domain);
TheServiceParticipant->shutdown();
return 0;
}
步骤五、执行make编译
执行$ACE_ROOT/bin/mwc.pl -type make产生Makefile,
执行make产生libHelloMsg_Common.so和发布订阅程序HelloMsgPub和HelloMsgSub
步骤六、运行发布订阅程序
HelloMsgPub -ORBDebugLevel 0 -DCPSDebugLevel 0 -DCPSTransportDebugLevel 0 -DCPSConfigFile ../../etc/dds_udp_conf.ini -ORBLogFile publisher.log
HelloMsgSub -ORBDebugLevel 0 -DCPSDebugLevel 0 -DCPSTransportDebugLevel 0 -DCPSConfigFile ../../etc/dds_udp_conf.ini -ORBLogFile subscriber.log
Linux平台的编译脚本compile.sh
$ACE_ROOT/bin/generate_export_file.pl HelloCommon > HelloCommon_Export.h
$ACE_ROOT/bin/mwc.pl -type make
make
---------------------
作者:pony12
来源:优快云
原文:https://blog.youkuaiyun.com/pony12/article/details/79309420
版权声明:本文为博主原创文章,转载请附上博文链接!