本文主要是介绍KY-RTI分布仿真技术:附录2 大联邦(构建1000个成员的HLA/RTI仿真系统),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
基于当前的RTI构建1000个以上成员的仿真系统在一些人看来似乎是极具挑战性的一个问题。如果你对当前的计算机技术、网络技术、仿真技术真正了解的话,其实构建这样的一个大规模仿真系统是完全可行的。本章以聊天程序为例,介绍了基于KY-RTI构建1000个仿真成员的两种方法:基于单个RTI服务器的大联邦;基于桥接程序实现多个RTI服务器的大联邦。从HLA的概念来讲,每个RTI服务器及其所有仿真成员可以称之为一个联邦,联邦之间不会发生数据通信;然而,本章的桥接程序能够实现多个RTI服务器之间的数据通信,也可以理解为多个联邦之间的数据通信;从而为大规模仿真提供了强有力支持。本章最后部分介绍了KY-RTI的桥接程序加入两个RTI服务器并将从一个RTI服务器接收到的数据转发到另外一个RTI服务器的源代码实现方法。另外,本章还简单探讨了以KY-RTI为代表的国产自主软件和DDS的个人看法。
11.1基于单个RTI服务器的大联邦
单个RTI服务器能否支持1000个成员的仿真系统,这一点与RTI本身的实现技术、仿真精度、仿真步长、网络延时、网络带宽等密切相关。通常,一般的RTI都无法做到这一点。下面是1000个仿真成员基于银河麒麟操作系统加入KY-RTI的示意图。上图是1000个仿真成员加入之前RTI服务器的状态;下图是1000个仿真成员加入RTI服务器之后的状态。从这一点也可以看出KY-RTI的大规模仿真支持能力。
图11.1 1000个仿真成员加入单个RTI服务器
通过单个RTI服务器实现1000个成员的仿真系统,与多个RTI服务器相比似乎具有一定的“瓶颈”特征,即数据集中于单个服务器不如分散于多个服务器。其实,随着网络技术的发展,特别是万兆以太网、5G技术的发展,网络延时大幅降低、网络带宽大幅提高,有些以前不可能实现的技术会成为可能;甚至具有同样计算能力的超级计算机的规模也会因此变小。
11.2基于桥接程序的多个RTI服务器的大联邦
KY-RTI除了单个RTI服务器支持1000个仿真成员外,也可以基于桥接程序把多个RTI服务器连接起来,从而实现更大规模的仿真系统。该方法特别适合于集群系统和部署于多个仿真应用机构的大规模仿真系统。
图11.2是基于银河麒麟操作系统进行的两个RTI服务器之间互操作演示示例,图11.3是相应的逻辑结构图。该例涉及到两个RTI服务器(RTI1和RTI2)和3个仿真成员(chat1、bridge、chat2)。两个RTI服务器RTI1、RTI2使用的端口号分别是10000和20000。
仿真成员chat1和bridge加入到RTI1;仿真成员chat2和bridge加入到RTI2。这3个仿真成员可以实现相互之间的聊天功能。从图11.2可以看到,当chat1说“I’m chat1”,bridge说“I’m bridge”,chat2说“I’m chat2”时,其他两个仿真成员都能够收到该仿真成员的聊天内容。
在这样的仿真系统中,桥接成员bridge起到了关键的作用,它可以把原本相互隔离的两个RTI服务器连接起来,共同实现更大规模的仿真。
图11.2 一个桥接程序加入两个RTI服务器的示例
图11.3 一个桥接程序加入两个RTI服务器的逻辑结构图
按照HLA的概念,每个RTI服务器及其仿真成员可以称之为一个联邦;两个RTI服务器涉及到两个联邦;联邦之间一般是不会通信的。因此,上图所示的联邦之间的通信不仅需要bridge支持,RTI本身也需要进行修改才能够实现。一般的RTI不会支持多联邦通信,除非你对其进行适当的改造。
在理解了前面两个图之后,使用桥接程序可以将多个RTI服务器以各种各样的方法进行互联,实现更大规模的仿真。
图11.4是图11.3的另外一种表示形式,一个桥接成员连接了两个RTI服务器,每个RTI服务器拥有1个仿真成员和1个桥接成员。桥接成员其实也是1个仿真成员,只是它的作用与一般的仿真成员不同,这里暂时把它们区分开吧。
图11.4 图11.3的另外一种表示形式
在图11.5中,每个RTI服务器拥有32个仿真成员和1个桥接成员。
图11.5 2个RTI服务器各自拥有32个仿真成员和1个桥接成员
图11.6是图11.5的简化形式。
图11.6 图11.5的简化形式
图11.7是3个RTI服务器通过桥接程序互联的情形。
图11.7 3个RTI服务器
图11.8是1个大联邦,中心是1个RTI服务器,它拥有32个桥接成员,每个桥接成员连接到另外一个RTI服务器;每个这样的RTI服务器除桥接成员外,含有32个仿真成员。这样,如果忽略桥接成员,整个系统共有32*32=1024个仿真成员。
由1000个以上仿真成员构成的大联邦可以采用各种各样的结构,图11.8只是其中的一种形式。可以采用层次式结构、网状结构、条状结构等。
图11.8适合集群部署方式,可以采用33个节点,每个节点部署1个RTI服务器。其中,一个节点部署32个桥接成员;其他节点各部署32个仿真成员和1个桥接成员。该图也适合大规模分布式仿真,可以部署于互联网上的多个地点。
图11.8 由1024个仿真成员构成的大联邦
11.3关于软件和DDS
在本文结束之前,就KY-RTI软件和DDS说点儿看法。
(1)可执行码。正如麒麟、中标、深度等国产操作系统一样,可执行码可以免费提供给大家使用;但不会得到更多的技术支持,并且可能存在部分限制;以麒麟操作系统为例,图11.2中的“[Unauthorized System]”表明这并不是一个得到了技术支持的操作系统,然而通常并不影响用户使用。国产操作系统在推广使用的过程中,得到了国内很多有实力单位的大力支持,包括项目和资金的支持,正是有了你们的支持,以国产操作系统为代表的自主软件才能够更好地发展,这对于研制和使用双方而言是共赢的。
(2)源代码。源代码不免费提供,需要者请联系作者(walt_lbq@163.com)。对于用户而言,即使获得了国产自主软件的源码,但没有技术支持,你会很难理解并做出本文所说的这么多事情。随着技术的进步,RTI的设计方法和性能都会得到进一步的发展和提高;除了把KY-RTI换个名外,你真的知道怎么做吗? 如果针对你的仿真系统做进一步的功能扩展,或者裁剪RTI功能,你能顺利做到吗?
(3)DDS(Data Distribution Service,数据分发服务)。DDS定义了一套用于分布式程序基于主题的发布订阅机制,相当于HLA中的公布订购机制。从仿真应用程序接口API角度来看,DDS仅相当于实现了HLA的部分功能;并且需要用户定义自己的API,这样就会导致不同的仿真系统难以集成到一起的问题;而这正是为什么要提出HLA标准的重要原因。当前,国内部分仿真系统采用DDS来取代RTI的实现方法,RTI似乎落后了;其实,DDS从提出到第1个软件实现,比HLA标准的提出还要早好几年,如果DDS能够取代RTI,那么提出HLA的那些DMSO仿真专家难道是一堆傻瓜吗?有人说,DDS似乎在QoS(Quality of Service,服务质量)和实时性方面更胜一筹;实际上,这是软件层面的事情,能不能做到这两点,与具体的实现软件有关系,与一个标准有多大关系呢?如果你觉得DDS不错,你可以把它用在RTI的底层;或者在RTI的底层采用DDS软件的一些实现方法。HLA基于已经设定的API实现程序之间的互操作,能够很好地支持仿真应用程序的互联互通;这一点是DDS所不具备的。
11.4桥接程序的源代码实现方法
大家应该对桥接程序的源代码实现方法比较好奇吧,相信绝大多数人都没有见过。该程序其实非常简单,熟悉HLA/RTI编程的用户一看就懂。本节的桥接程序对应图11.2中的桥接成员,采用GNU C++实现,当然也可以采用其他程序设计语言实现。一个桥接成员可以加入到两个RTI服务器,而这两个RTI服务器可能运行于不同地点的不同操作系统主机上;譬如一个是北京的Windows机器,一个是长沙的银河麒麟机器。
桥接程序包含3个.cpp文件:Chat.cpp、HwFederateAmbassador1.cpp和HwFederateAmbassador2.cpp。
(1)Chat.cpp负责在两个RTI服务器上创建联邦、加入联邦、公布和订购数据、像一般仿真成员一样发送数据;仿真完成时退出联邦。
(2)HwFederateAmbassador1.cpp负责从RTI1服务器接收数据,并将其转发到RTI2服务器。
(3)HwFederateAmbassador2.cpp负责从RTI2服务器接收数据,并将其转发到RTI1服务器。
表11.1 大联邦聊天示例:chat.cpp
- #include "HwFederateAmbassador1.hh"
- #include "HwFederateAmbassador2.hh"
- #include <RTI.hh>
- #include <fedtime.hh>
- #include <iostream>
- using namespace std;
- RTI::InteractionClassHandle hChatClass_1;
- RTI::ParameterHandle hChatName_1;
- RTI::ParameterHandle hChatSentence_1;
- RTI::InteractionClassHandle hChatClass_2;
- RTI::ParameterHandle hChatName_2;
- RTI::ParameterHandle hChatSentence_2;
- RTI::RTIambassador rti1;
- RTI::RTIambassador rti2;
- int hw_main(int argc, char *argv[])
- {
- const char *federationExecutionName1 = "chat";
- const char *federationExecutionName2 = "chat";
- const char *FEDfile = "chat.fed";
- char federateName[50];
- cout << "Please input your name: ";
- cin >> federateName;
- try
- {
- HwFederateAmbassador1 fedAmb1;
- HwFederateAmbassador2 fedAmb2;
- RTI::FederateHandle federateId1;
- RTI::FederateHandle federateId2;
- try
- {
- //若不带IP地址和端口号则从RTI.rid中读取: rti1.createFederationExecution(federationExecutionName, FEDfile);
- //IP地址和端口号由用户自己设置, 用户可以从自己的配置文件或图形窗口中获取.
- rti1.createFederationExecution(federationExecutionName1, FEDfile, "127.0.0.1", "10000");
- //2条创建联邦语句不要写在一起.
- //rti2.createFederationExecution(federationExecutionName2, FEDfile, "127.0.0.1", "20000");
- }
- catch ( RTI::Exception& e )
- {
- }
- try
- {
- //IP地址和端口号由用户自己设置, 用户可以从自己的配置文件或图形窗口中获取.
- rti2.createFederationExecution(federationExecutionName2, FEDfile, "127.0.0.1", "20000");
- }
- catch ( RTI::Exception& e )
- {
- }
- try
- {
- federateId1 = rti1.joinFederationExecution(federateName, federationExecutionName1, &fedAmb1);
- federateId2 = rti2.joinFederationExecution(federateName, federationExecutionName2, &fedAmb2);
- }
- catch ( RTI::Exception& e )
- {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- ///
- hChatClass_1 = rti1.getInteractionClassHandle("chat");
- hChatName_1 = rti1.getParameterHandle("name", hChatClass_1);
- hChatSentence_1 = rti1.getParameterHandle("sentence", hChatClass_1);
- hChatClass_2 = rti1.getInteractionClassHandle("chat");
- hChatName_2 = rti1.getParameterHandle("name", hChatClass_2);
- hChatSentence_2 = rti1.getParameterHandle("sentence", hChatClass_2);
- //如果向外发送,则需要公布
- rti1.publishInteractionClass(hChatClass_1);
- rti2.publishInteractionClass(hChatClass_2);
- //如果需要接收,则必须订购
- rti1.subscribeInteractionClass(hChatClass_1);
- rti2.subscribeInteractionClass(hChatClass_2);
- string szSentence;
- cin.ignore();
- while (0 != strcmp(szSentence.c_str(), "exit"))
- {
- cout << "Please input a sentence: ";
- getline(cin, szSentence);
- try {
- RTI::ParameterHandleValuePairSet* pParams = NULL;
- long numParams(2);
- pParams = RTI::ParameterSetFactory::create (numParams);
- pParams->add(hChatName_1,(char*)federateName, strlen(federateName)+1);
- pParams->add(hChatSentence_1,(char*)szSentence.c_str(), szSentence.size());
- rti1.sendInteraction(hChatClass_1, *pParams, "");
- pParams->empty();
- delete pParams;
- pParams = RTI::ParameterSetFactory::create (numParams);
- pParams->add(hChatName_2,(char*)federateName, strlen(federateName)+1);
- pParams->add(hChatSentence_2,(char*)szSentence.c_str(), szSentence.size());
- rti2.sendInteraction(hChatClass_2, *pParams, "");
- pParams->empty();
- delete pParams;
- }
- catch(...)
- {
- cerr << "Error: send interaction" << endl;
- }
- }
- try
- {
- rti1.resignFederationExecution( RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES );
- rti2.resignFederationExecution( RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES );
- rti1.destroyFederationExecution( federationExecutionName1 );
- rti2.destroyFederationExecution( federationExecutionName2 );
- }
- catch ( RTI::Exception& e )
- {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- }
- catch ( RTI::Exception& e )
- {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- return 0;
- }
- int
- main(int argc, char** argv)
- {
- return hw_main(argc, argv);
- }
|
表11.2 大联邦聊天示例:HwFederateAmbassador1.cpp
- #include "fedtime.hh"
- #include "HwFederateAmbassador1.hh"
- #include <iostream>
- using namespace std;
- extern RTI::InteractionClassHandle hChatClass_1;
- extern RTI::ParameterHandle hChatName_1;
- extern RTI::ParameterHandle hChatSentence_1;
- extern RTI::RTIambassador rti2;
- void HwFederateAmbassador1::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const RTI::FedTime& theTime, // supplied C4
- const char *theTag, // supplied C4
- RTI::EventRetractionHandle theHandle) // supplied C1
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::InvalidFederationTime,
- RTI::FederateInternalError)
- {
- //call the next service.
- this->receiveInteraction( theInteraction, theParameters, theTag );
- }
- void HwFederateAmbassador1::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const char *theTag) // supplied C4
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::FederateInternalError)
- {
- RTI::ParameterHandle paraHandle;
- RTI::ULong valueLength;
- //Usage of char[] and string
- char name[256]; //name of sender
- string sentence; //sentence of sender
- if(theInteraction == hChatClass_1) {
- for ( int i = 0; i < theParameters.size(); i++ )
- {
- paraHandle = theParameters.getHandle( i );
- if(paraHandle == hChatName_1) {
- theParameters.getValue(i, (char*)name, valueLength);
- /*If name is a double number, you can do this way.
- double name;
- theParameters.getValue(i, (char*)&name, valueLength);
- */
- }else if(paraHandle == hChatSentence_1) {
- sentence.resize(theParameters.getValueLength(i));
- theParameters.getValue(i, (char*)sentence.c_str(), valueLength);
- }else{
- cout << "Federation1: Receive wrong parameter handle." << endl;
- }
- }
- cout << endl << "Federation1: " << name << ": " << sentence << endl;
- //转发到rti2
- rti2.sendInteraction(theInteraction, theParameters, theTag);
- }
- }
|
表11.3 大联邦聊天示例:HwFederateAmbassador2.cpp
- #include "fedtime.hh"
- #include "HwFederateAmbassador2.hh"
- #include <iostream>
- using namespace std;
- extern RTI::InteractionClassHandle hChatClass_2;
- extern RTI::ParameterHandle hChatName_2;
- extern RTI::ParameterHandle hChatSentence_2;
- extern RTI::RTIambassador rti1;
- void HwFederateAmbassador2::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const RTI::FedTime& theTime, // supplied C4
- const char *theTag, // supplied C4
- RTI::EventRetractionHandle theHandle) // supplied C1
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::InvalidFederationTime,
- RTI::FederateInternalError)
- {
- //call the next service.
- this->receiveInteraction( theInteraction, theParameters, theTag );
- }
- void HwFederateAmbassador2::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const char *theTag) // supplied C4
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::FederateInternalError)
- {
- RTI::ParameterHandle paraHandle;
- RTI::ULong valueLength;
- //Usage of char[] and string
- char name[256]; //name of sender
- string sentence; //sentence of sender
- if(theInteraction == hChatClass_2) {
- for ( int i = 0; i < theParameters.size(); i++ )
- {
- paraHandle = theParameters.getHandle( i );
- if(paraHandle == hChatName_2) {
- theParameters.getValue(i, (char*)name, valueLength);
- /*If name is a double number, you can do this way.
- double name;
- theParameters.getValue(i, (char*)&name, valueLength);
- */
- }else if(paraHandle == hChatSentence_2) {
- sentence.resize(theParameters.getValueLength(i));
- theParameters.getValue(i, (char*)sentence.c_str(), valueLength);
- }else{
- cout << "Federation2: Receive wrong parameter handle." << endl;
- }
- }
- cout << endl << "Federation2: " << name << ": " << sentence << endl;
- //转发到rti1
- rti1.sendInteraction(theInteraction, theParameters, theTag);
- }
- }
|
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分布仿真技术:附录1 分组聊天(HLA数据分发管理的应用)
KY-RTI分布仿真技术:附录2 大联邦(构建1000个成员的HLA/RTI仿真系统)
KY-RTI分布仿真技术:附录3 国产化(操作系统+CPUs)
这篇关于KY-RTI分布仿真技术:附录2 大联邦(构建1000个成员的HLA/RTI仿真系统)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!