KY-RTI分布仿真技术:附录1 分组聊天(HLA数据分发管理的应用)

       本章从RTI开发者的角度简单地介绍HLA1.3标准中的数据分发管理(DDM,Data Distributed Management)并给出了一个具体的示例。前面介绍了基于各种程序设计语言开发的聊天程序示例,一个仿真成员的聊天内容会被发送给所有其他仿真成员;但能不能将仿真成员进行分组,组内的成员在聊天时不影响其他组呢?HLA数据分发管理可以完美地实现这一功能,甚至实现更进一步的功能:将仿真成员分组,一个仿真成员可以向任意组内的仿真成员发送消息;当然自己除外,因为HLA标准规定一个仿真成员不会收到自己发送的消息,自己发送的消息没有必要在网络上走一圈再送给自己。

10.1 HLA的数据过滤机制

       HLA是一个数据交换的标准,仿真成员通过RTI软件交换数据。HLA为数据交换提供了两种过滤机制:

       (1)声明管理服务

       声明管理服务主要包含对象类和交互类的公布、订购、取消公布、取消订购等一系列服务。以战场仿真为例,如果一个仿真成员订购了对象类plane,则它会收到任何该对象类实例所更新的属性值;以本文的聊天程序为例,如果一个仿真成员订购了交互类chat,则它会收到任何其他人的聊天内容。

       (2)数据分发管理服务

       数据分发管理服务提供了更精细的数据过滤方法。以战场仿真为例,一个仿真成员在订购对象类plane时可以加一个“限制”,当一个plane对象实例在更新属性时也带一个“限制”,在HLA1.3标准中这个“限制”称之为区域“region”。我们把前一个区域称之为“订购区域”,后一个区域称之为“更新区域”,当两个区域有部分重叠时,则订购者会收到发送者发送的数据;以本文的聊天程序为例,如果一个仿真成员在订购交互类时带一个“订购区域”,发送交互时带一个“发送区域”,则仅当两个区域有部分重叠时,则订购者会收到发送者发送的聊天内容。这就意味着,如果将“订购区域”分为2个组,则发送者可以向任意一个组发送聊天内容。

10.2 数据分发管理中的概念

       如图10.1所示,本节以红蓝双方的战场仿真为例,简单地介绍数据分发管理中的相关概念。

       (1)routing space(路由空间):路由空间可以理解为整个仿真空间。

       路由空间可以定义自己的维“dimension”。在HLA中,正如“联邦”代表整个系统,是一个“虚”的概念,它到底代表所有的人、所有的机器、所有的程序还是其他什么呢?路由空间也是一个“虚”的概念,不特指某个具体的空间。

       (2)region(区域):一个区域包含多个分域(extent)。图10.1可以理解为有3支红方部队要去攻占蓝方的2个山头。红方区域包含3个分域,每个分域可以理解为1支部队的部署态势;蓝方区域包含2个分域,每个分域可以理解为1个山头。

       区域没有维的概念。你可以把它理解为一个集合,该集合中含有若干个分域。

       (3)extent(分域):本文把extent称之为分域,有些文章中称之为“限域”。

       分域有维的概念,是区域中的一个具体的小空间。在数学上,如果每个集合只包含1个元素,那么我们可以离开“集合”这个概念,而直接讨论其中的元素就可以了。类似地,假设规定每个区域只有1个分域,那么HLA中可以去掉区域的概念,而直接讨论分域;由此分域与路由空间这两个概念就更容易理解了,两者都有“维”的概念,前者是由多个“维”构成的具体空间;后者是由多个“维”构成的“虚”空间。

       一个具体空间的大小是有尺寸的,而“虚”空间的尺寸则无限大(不超过32位的最大整数)。这样,就引入了range的概念。

       (4)range(范围):将一个“维”的上界和下界定义后就是范围。有人可能会说,本次仿真规定,“作战范围为方圆300千米”,这是路由空间的范围吗?其实,在RTI中,你没有办法去设置一个路由空间的范围,你只能设置一个分域中维的范围。前面的一句话意味着每个分域的范围在方圆300千米之内。当你设置维的范围之后,这就意味着由多个维构成的分域是一个方形空间,绝对不会是一个类似三角形、菱形、五角星、六边形之类的奇怪形状。

       (5)dimension(维):不要简单地将“维”理解为三维空间中的“维”,任何属性都可以定义为一个“维”。譬如面包师傅每天做“咸”和“甜”两种面包,则面包的这种“味道”就是面包的一个属性,可以定义为一个“维”;从公布订购关系来看,面包师傅公布“咸”和“甜”两种面包,顾客按照自己的喜好订购这两类面包,快递员(RTI)按照顾客的需求负责将面包配送给顾客。在后面的聊天程序中,按照仿真成员句柄的奇偶特性分为2组,这也是一个维。

       在HLA1.3标准中,“维”必须定义为大于等于0的整数,不能超过32位整数的最大值。假设最大值为1000,如果你需要的最大值为2000,则可用的一种办法是对各个数进行线性化处理,将所有的值除以2,于是2000/2=1000满足要求。

       (6)overlap(重叠):图10.1定义了红方区域和蓝方区域,如果任意一个红方分域与任意一个蓝方分域相交,则称两个区域重叠。

                                                                            图10.1 数据分发管理中的概念

10.3项目设计

       当仿真成员加入联邦时,RTI会返回一个句柄。如图10.2所示,本项目根据该句柄的奇偶数将所有仿真成员分为两组:group0为偶数,group1为奇数。两个组内的成员互相通信,组间不能通信。在程序中使用了订购区域和发送区域,稍微修改一下代码,则可以做到向任何一个组发送消息。

                                                                                        图10.2两个分组

       每条聊天信息应包含2个内容:聊天者昵称、聊天的一句话,这样接收者就会知道是谁在发言。将聊天信息封装为一个交互类chat_group,“聊天者昵称”用name表示,“聊天的一句话”用sentence表示,两个都是字符串类型。聊天程序使用的FED文件如表10.1所示,该文件可使用KY-OMT对象模型模板工具自动生成。

                                                 表10.1  C++分组聊天示例:chat_ddm.fed

  1. (FED
  2.   (Federation fed_example)
  3.   (FEDversion v1.3)
  4.   (spaces
  5.     (space group
  6.       (dimension groupid)
  7.     )
  8.   )
  9.   (interactions
  10.     (class InteractionRoot reliable receive
  11.       (class RTIprivate reliable receive)
  12.       (class chat_group reliable receive group
  13.         (parameter name)
  14.         (parameter sentence)
  15.       )
  16.     )
  17.   )
  18. )

       从表10.1可以看到,“spaces”部分定义了一个名为“group”的路由空间,它有1个“groupid”维。

       从字面意义上看,“spaces”是一个英语复数名词,意味着在其中可以定义多个“space”,每个“space”都是一个路由空间。这就是说,一个仿真可以定义多个路由空间。譬如对战场仿真而言,所有的飞机和雷达可以将整个三维战场空间作为它们的路由空间;而“红方部队”、“蓝方部队”则可以将“参战部队”作为它们的路由空间,其取值范围就是“红方部队”和“蓝方部队”这两个枚举值,相当于本例中的group0和group1两个聊天小组。

10.4代码设计

       该程序比较简单,一个Chat.cpp和HwFederateAmbassador.cpp就可以实现。前者通过调用创建联邦执行、加入联邦执行、创建区域、设计区域的分域中的维的上下界、公布交互类、带区域订购交互类、带区域发送交互,仿真完成时退出联邦;后者用来接收RTI的回调消息,当订购区域与发送区域重叠时,会收到发送方的数据。

       本项目对时间没有特别要求,不需要采用HLA时间管理机制。当RTI收到聊天信息时就立即发送给其他人,不需要调用tick服务。

       Chat.cpp代码说明:

11-13行:定义交互类及其参数句柄变量;

31-40行:创建联邦执行;

42-59行:加入联邦执行;

44行:根据返回的仿真成员句柄设置分组号;

63-65行:获取交互类及其参数句柄;

67-68行:获取路由空间和维句柄;

72行:定义发送区域;

73行:定义订购区域;

75-76行:设置发送区域的extent0分域中维的上下界;

77行:通知RTI更新发送区域;

79-80行:设置订购区域的extent0分域中维的上下界;

81行:通知RTI更新订购区域;

85行:公布交互类,只有公布之后才能够向RTI发送交互;

87行:带区域订购交互类,只有订购并且区域匹配之后才能够从RTI收到其他人的聊天内容;

91-114行:循环操作,每次输入一句话,并调用sendInteraction服务发送给RTI;当用户输入“exit”时则退出执行;

104-107行:带区域发送交互;

116-121行:退出联邦执行,不再参加仿真;

123-134行:销毁联邦。如果是最后一个仿真成员执行该操作,则整个仿真结束。

                                                       表10.2  C++分组聊天示例:chat.cpp

  1. #include "HwFederateAmbassador.hh"
  2. #include <RTI.hh>
  3. #include <fedtime.hh>
  4. #include <iostream>
  5. using namespace std;
  6. /*
  7.   本程序有2个分组,一个人的聊天内容只能被同组中的人看到.
  8.   使用HLA的数据分发管理服务(DDM)来实现,分组必须为[0, 4294967295)间的整数.
  9. */
  10. RTI::InteractionClassHandle     hChatClass;
  11. RTI::ParameterHandle        hChatName;
  12. RTI::ParameterHandle        hChatSentence;
  13. int mygroup = 0; //取值01,本程序有2个分组
  14. int hw_main(int argc, char *argv[]) {
  15.     const char *federationExecutionName = "chat";
  16.     const char *FEDfile = "chat_ddm.fed"; //本例使用chat_ddm.fed
  17.     char federateName[50];
  18.     cout << "Please input your name: ";
  19.     cin >> federateName;
  20.     try {
  21.         RTI::RTIambassador       rti;
  22.         HwFederateAmbassador     fedAmb;
  23.         RTI::FederateHandle      federateId;
  24.         try {
  25.             rti.createFederationExecution(federationExecutionName, FEDfile);
  26.         }
  27.         catch ( RTI::FederationExecutionAlreadyExists& e ) {
  28.             //According to the HLA standard, only the first federate can call this service succesfully.
  29.             //cerr << "FED_HW: Note: Federation execution already exists." << e << endl;
  30.         } catch ( RTI::Exception& e ) {
  31.             cerr << "FED_HW: ERROR:" << e << endl;
  32.             return -1;
  33.         }
  34.         try {
  35.             federateId = rti.joinFederationExecution(federateName,
                                               
     federationExecutionName, &fedAmb);
  36.             mygroup = federateId % 2; //取值01,本程序有2个分组
  37.             cout << "***I am in group " << mygroup << "***" << endl;
  38.         } catch (RTI::FederateAlreadyExecutionMember& e) {
  39.             cerr << "FED_HW: ERROR: " << argv[1]
  40.                  << " already exists in the Federation Execution "
  41.                  << federationExecutionName << "." << endl;
  42.             cerr << e << endl;
  43.             return -1;
  44.         } catch (RTI::FederationExecutionDoesNotExist&) {
  45.             cerr << "FED_HW: ERROR: Federation Execution "
  46.                  << "does not exists."<< endl;
  47.             return -1;
  48.         } catch ( RTI::Exception& e ) {
  49.             cerr << "FED_HW: ERROR:" << e << endl;
  50.             return -1;
  51.         }
  52.         ///
  53.         hChatClass = rti.getInteractionClassHandle("chat_group"); //对应chat_ddm.fed中的chat_group
  54.         hChatName = rti.getParameterHandle("name", hChatClass);
  55.         hChatSentence = rti.getParameterHandle("sentence", hChatClass);
  56.         RTI::SpaceHandle  hGroup = rti.getRoutingSpaceHandle("group"); //对应chat_ddm.fed中的group
  57.         RTI::DimensionHandle  hGroupid = rti.getDimensionHandle("groupid", hGroup);
  58.         //-------------------------------------------------
  59.         //本例实际上只需要一个group即可,这里定义两个group,分别用于发送和接收,
            //其实二者可以使用相同的group.
  60.         RTI::Region* send_group = rti.createRegion(hGroup, 1); //只有1extent,即extent0
  61.         RTI::Region* receive_group = rti.createRegion(hGroup, 1); //只有1extent,即extent0
  62.         send_group->setRangeLowerBound(0, 0, mygroup);
                                //extent0的第0维为groupid,设置其下界为mygroup
  63.         send_group->setRangeUpperBound(0, 0, mygroup);
                                //extent0的第0维为groupid,设置其上界为mygroup
  64.         rti.notifyAboutRegionModification(*send_group); //通知RTI更改
  65.         receive_group->setRangeLowerBound(0, 0, mygroup);
                                //extent0的第0维为groupid,设置其下界为mygroup
  66.         receive_group->setRangeUpperBound(0, 0, mygroup);
                                //extent0的第0维为groupid,设置其上界为mygroup
  67.         rti.notifyAboutRegionModification(*receive_group); //通知RTI更改
  68.         //-------------------------------------------------
  69.         //如果向外发送,则需要公布
  70.         rti.publishInteractionClass(hChatClass); //没有后缀WithRegion
  71.         //如果需要接收,则必须订购
  72.         rti.subscribeInteractionClassWithRegion(hChatClass, *receive_group); //有后缀WithRegion
  73.         string szSentence;
  74.         cin.ignore();
  75.         while (0 != strcmp(szSentence.c_str(), "exit")) {
  76.             cout << "Please input a sentence: ";
  77.             getline(cin, szSentence);
  78.             RTI::ParameterHandleValuePairSet* pParams = NULL;
  79.             long numParams(2);
  80.             pParams = RTI::ParameterSetFactory::create (numParams);
  81.             pParams->add(hChatName,(char*)federateName, strlen(federateName)+1);
  82.             pParams->add(hChatSentence,(char*)szSentence.c_str(), szSentence.size());
  83.             try {
  84.                 //这里演示如何使用HLA中的tag,tag是一个字符串,设置为"0""1"
  85.                 if(mygroup == 0)
  86.                     rti.sendInteractionWithRegion(hChatClass, *pParams, "0", *send_group);  //有后缀WithRegion
  87.                 else
  88.                     rti.sendInteractionWithRegion(hChatClass, *pParams, "1", *send_group);  //有后缀WithRegion
  89.             } catch(...) {
  90.                 cerr << "Error: send interaction" << endl;
  91.             }
  92.             pParams->empty();
  93.             delete pParams;   // Deallocate the memory
  94.         }
  95.         try {
  96.             rti.resignFederationExecution( RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES );
  97.         } catch ( RTI::Exception& e ) {
  98.             cerr << "FED_HW: ERROR:" << e << endl;
  99.             return -1;
  100.         }
  101.         try {
  102.             rti.destroyFederationExecution( federationExecutionName );
  103.         } catch ( RTI::FederatesCurrentlyJoined& /* e */ ) {
  104.             cerr << "FED_HW: FederatesCurrentlyJoined" << endl;
  105.             return 0;
  106.         } catch ( RTI::FederationExecutionDoesNotExist& /* e */) {
  107.             cerr << "FED_HW: FederationExecutionDoesNotExist" << endl;
  108.             return 0;
  109.         } catch ( RTI::Exception& e ) {
  110.             cerr << "FED_HW: ERROR:" << e << endl;
  111.             return -1;
  112.         }
  113.     } catch (RTI::ConcurrentAccessAttempted& e) {
  114.         cerr << e << endl;
  115.         return -1;
  116.     } catch ( RTI::Exception& e ) {
  117.         cerr << "FED_HW: ERROR:" << e << endl;
  118.         return -1;
  119.     }
  120.     return 0;
  121. }
  122. int
  123. main(int argc, char** argv) {
  124.     return hw_main(argc, argv);
  125. }

       回调消息没有订购区域和发送区域之分。HwFederateAmbassador.cpp代码说明:

10-24行:由于不处理时间参数,因此如果接收到这种类型的receiveInteraction交互,则直接调用不带时间参数的服务来统一处理;

26-65行:处理接收到的聊天信息并输出,tag按原样输出。

                                               表10.3  C++分组聊天示例:HwFederateAmbassador.cpp

  1. #include "fedtime.hh"
  2. #include "HwFederateAmbassador.hh"
  3. #include <iostream>
  4. using namespace std;
  5. extern RTI::InteractionClassHandle     hChatClass;
  6. extern RTI::ParameterHandle            hChatName;
  7. extern RTI::ParameterHandle            hChatSentence;
  8. void HwFederateAmbassador::receiveInteraction (
  9.     RTI::InteractionClassHandle       theInteraction, // supplied C1
  10.     const RTI::ParameterHandleValuePairSet& theParameters,  // supplied C4
  11.     const RTI::FedTime&                  theTime,        // supplied C4
  12.     const char                                    *theTag,         // supplied C4
  13.     RTI::EventRetractionHandle        theHandle)      // supplied C1
  14. throw (
  15.     RTI::InteractionClassNotKnown,
  16.     RTI::InteractionParameterNotKnown,
  17.     RTI::InvalidFederationTime,
  18.     RTI::FederateInternalError)
  19. {
  20.     //call the next service.
  21.     this->receiveInteraction( theInteraction, theParameters, theTag );
  22. }
  23. void HwFederateAmbassador::receiveInteraction (
  24.     RTI::InteractionClassHandle       theInteraction, // supplied C1
  25.     const RTI::ParameterHandleValuePairSet& theParameters,  // supplied C4
  26.     const char                                   *theTag)         // supplied C4
  27. throw (
  28.     RTI::InteractionClassNotKnown,
  29.     RTI::InteractionParameterNotKnown,
  30.     RTI::FederateInternalError)
  31. {
  32.     RTI::ParameterHandle paraHandle;
  33.     RTI::ULong           valueLength;
  34.     //Usage of char[] and string
  35.     char name[256];   //name of sender
  36.     string sentence;  //sentence of sender
  37.     if(theInteraction == hChatClass) {
  38.         for ( int i = 0; i < theParameters.size(); i++ ) {
  39.             paraHandle = theParameters.getHandle( i );
  40.             if(paraHandle == hChatName) {
  41.                 theParameters.getValue(i, (char*)name, valueLength);
  42.                 /*If name is a double number, you can do this way.
  43.                     double name;
  44.                     theParameters.getValue(i, (char*)&name, valueLength);
  45.                 */
  46.             } else if(paraHandle == hChatSentence) {
  47.                 sentence.resize(theParameters.getValueLength(i));
  48.                 theParameters.getValue(i, (char*)sentence.c_str(), valueLength);
  49.             } else {
  50.                 cout << "Receive wrong parameter handle." << endl;
  51.             }
  52.         }
  53.         cout << endl << name << "(group " << theTag << "): " << sentence << endl;
  54.     }
  55. }

KY-RTI的Linux、Windows版本和源码请联系作者:walt_lbq@163.com

KY-RTI分布仿真技术:前 言

KY-RTI分布仿真技术:第一章 简介

KY-RTI分布仿真技术:第二章 系统安装

KY-RTI分布仿真技术:第三章 KY-OMT对象模型模板工具

KY-RTI分布仿真技术:第四章 C++程序设计

KY-RTI分布仿真技术:第五章 Qt程序设计

KY-RTI分布仿真技术:第六章 Java程序设计

KY-RTI分布仿真技术:第七章 Visual C++程序设计

KY-RTI分布仿真技术:第八章 Visual C#程序设计

KY-RTI分布仿真技术:第九章 综合演示

KY-RTI分布仿真技术:第十章 Python程序设计

KY-RTI分布仿真技术:附录1 分组聊天(HLA数据分发管理的应用

KY-RTI分布仿真技术:附录2 大联邦(构建1000个成员的HLA/RTI仿真系统)

KY-RTI分布仿真技术:附录3 国产化(操作系统+CPUs)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值