基于OpenDDS开发发布订阅HelloMsg程序的过程(Linux)

有对DDS技术了解、学习、开发和培训需求的,请加入QQ群:707895641(DDS专业技术辅导)。

***************************************************************************************************

       基于OpenDDS的应用开发(Linux),大体和Windows平台类似,也分两个部分的工作:

(1)定义自己的IDL文件,并编译成传输数据类型通讯动态库.so文件;

(2)分别编写pub和sub程序,运行

        具体步骤,有以下几个:

  1. 定义idl文件,如HelloMsg.ild
  2. 运行脚本,产生相应的消息类型符号导出头文件HelloMsgCommon_Export.h
  3. 编写mwc、mpc工作台和项目文件,如HelloMsg.mwc、HelloMsg.mpc
  4. 编写HelloMsgPub.cpp和HelloMsgSub.cpp代码;
  5. 执行make编译,产生动态库libHelloMsgCommon.so、HelloMsgPub、HelloMsgSub
  6. 运行发布和订阅程序,查看运行结果

步骤一、定义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
**************************************************************************************************************
*****有对DDS技术了解、学习、开发和培训需求的,欢迎加入QQ群:707895641(DDS专业技术辅导)*****

**************************************************************************************************************

猜你喜欢

转载自blog.csdn.net/pony12/article/details/79309420
今日推荐