1. 程式人生 > >麒麟KY-RTI分佈模擬技術:第六章 Java程式設計

麒麟KY-RTI分佈模擬技術:第六章 Java程式設計

       本章講述瞭如何基於Java設計聊天程式和時間管理程式,兩個程式都是控制檯程式。聊天程式相當於4.3節的GNU C++聊天程式;時間管理程式相當於4.4節的GNU C++程式。對於不同的程式設計語言而言,基於HLA/RTI設計模擬應用的方法都差不多,其關鍵在於RTI軟體能否支援相應程式設計語言的開發,使用者只需要關心一下呼叫介面即可,通過呼叫介面可以設計形式多樣的程式。與C++呼叫介面的一個顯著區別在於控制代碼和時間的表示,Java中的各種控制代碼全部用int表示,各類時間則用double表示。

6.1 聊天程式

6.1.1需求分析

       本專案需要實現一個類似微信群或者QQ群聊天功能的Java程式,每個人傳送的訊息都能夠被群裡的其他人看到。

6.1.2專案設計

       每條聊天資訊應包含2個內容:聊天者暱稱、聊天的一句話,這樣接收者就會知道是誰在發言。“聊天者暱稱”用name表示,“聊天的一句話”用sentence表示,兩個都是字串型別。因為HLA是面向物件的,傳送的資料要麼採用物件類,要麼採用互動類。本專案可採用互動類,將name和sentence封裝到一個名叫“chat”的互動類中,如下列虛擬碼所示。

class chat {           //互動類

       int  name;     //引數

       int  sentence; //引數

}

       下面採用KY-OMT建立fed檔案,相應的chat.fed檔案已經在3.3.3中建立完成,將該檔案儲存到KY-RTI的bin目錄。

       本專案對時間沒有特別要求,不需要採用HLA時間管理機制。在採用Java語言開發時,不要使用tick服務,否則會報一個警告。

6.1.3程式碼設計

       該程式由3個原始檔組成:GlobalVariables.java、Chat.java、HwFederateAmbassador.java。GlobalVariables.java定義了其他兩個檔案需要用到的公用變數;Chat.java呼叫RTI服務訪問RTI;HwFederateAmbassador.java接收RTI回撥服務。

       GlobalVariables.java定義了可由Chat.java、HwFederateAmbassador.java共享使用的靜態變數;因為Java不支援C++的全域性變數概念,這裡的靜態變數就相當於C++的全域性變數。

                                      表6.1  Java聊天示例:GlobalVariables.java

  1. public class GlobalVariables
  2. {
  3.     public static int        hChatClass;
  4.     public static int        hChatName;
  5.     public static int        hChatSentence;
  6. }

       Chat.java程式碼說明:

21-25行:建立聯邦執行;

27-33行:加入聯邦執行;

36-38行:獲取互動類及其引數控制代碼;

41行:公佈互動類,只有公佈之後才能夠向RTI傳送互動;

43行:訂購互動類,只有訂購之後才能夠從RTI收到其他人的聊天內容;

46-59行:迴圈操作,每次輸入一句話,並呼叫sendInteraction服務傳送給RTI;當用戶輸入“exit”時則退出執行;

65行:該行為註釋行,表示模擬成員在結束時不需要呼叫'resignFederationExecution'和 'destroyFederationExecution'服務,RTI伺服器會自動執行這兩個服務。

                                      表6.2  Java聊天示例:Chat.java

  1. import MID.*;
  2. import RTI.*;
  3. public class Chat
  4. {
  5.     public static void main(String[] args) {
  6.         String federationName = "chat";
  7.         String federateName = System.console().readLine("Please input your name: ");
  8.         HwFederateAmbassador fed;
  9.         RTI_RTIambassador rti;
  10.         try {
  11.             fed = new HwFederateAmbassador();
  12.             rti = new RTI_RTIambassador();
  13.         } catch(Exception ex) {
  14.             ex.printStackTrace();
  15.             return;
  16.         }
  17.         try {
  18.             rti.createFederationExecution(federationName, "chat.fed");
  19.         } catch(Exception ex) {
  20.             // According to the HLA standard, only the first federate can call createFederationExecution successfully. Don't return.
  21.         }
  22.         try {
  23.             int federateHandle = rti.joinFederationExecution(federateName, federationName, fed);
  24.             //System.out.println("my federate handle is "+federateHandle);
  25.         } catch(Exception ex) {
  26.             ex.printStackTrace();
  27.             return;
  28.         }
  29.         try {
  30.             GlobalVariables.hChatClass = rti.getInteractionClassHandle("chat");
  31.             GlobalVariables.hChatName = rti.getParameterHandle("name", GlobalVariables.hChatClass);
  32.             GlobalVariables.hChatSentence = rti.getParameterHandle("sentence", GlobalVariables.hChatClass);
  33.             //如果向外傳送,則需要公佈
  34.             rti.publishInteractionClass(GlobalVariables.hChatClass);
  35.             //如果需要接收,則必須訂購
  36.             rti.subscribeInteractionClass(GlobalVariables.hChatClass);
  37.             String szSentence = "";
  38.             while (!szSentence.equals("exit")) {
  39.                 szSentence = System.console().readLine("Please input a sentence: ");
  40.                 HandleValuePair[] theParameters = new HandleValuePair[2];
  41.                 theParameters[0] = new HandleValuePair();
  42.                 theParameters[0].aHandle = GlobalVariables.hChatName;
  43.                 theParameters[0].aValue = federateName; //int -> String
  44.                 theParameters[1] = new HandleValuePair();
  45.                 theParameters[1].aHandle = GlobalVariables.hChatSentence;
  46.                 theParameters[1].aValue = szSentence; //int -> String
  47.                 rti.sendInteraction(GlobalVariables.hChatClass, theParameters, "");
  48.             }
  49.         } catch (Exception ex) {
  50.             ex.printStackTrace();
  51.             return;
  52.         }
  53.         //After the program exits, the RTI will automatically calls 'resignFederationExecution' and 'destroyFederationExecution'.
  54.     }
  55. }

       HwFederateAmbassador.java程式碼說明:

5-8行:由於不處理時間引數,因此如果接收到這種型別的receiveInteraction互動,則直接呼叫不帶時間引數的服務來統一處理;

10-28行:處理接收到的聊天資訊,將其簡單輸出即可。

                                      表6.3  Java聊天示例:HwFederateAmbassador.java

  1. import MID.*;
  2. public class HwFederateAmbassador extends RTIFederateAmbassador
  3. {
  4.     public final void receiveInteraction(int theInteraction, MID.HandleValuePair[] theParameters, double theTime, String theTag, MID.EventRetractionHandle theHandle) {
  5.         //call the next service.
  6.         receiveInteraction(theInteraction, theParameters, theTag);
  7.     }
  8.     public final void receiveInteraction(int theInteraction, MID.HandleValuePair[] theParameters, String theTag) {
  9.         String name = new String();     //name of sender
  10.         String sentence = new String(); //sentence of sender
  11.         for ( int i = 0; i < theParameters.length; i++ ) {
  12.             if (theParameters[i].aHandle == GlobalVariables.hChatName) {
  13.                 name = theParameters[i].aValue;
  14.             } else if (theParameters[i].aHandle == GlobalVariables.hChatSentence) {
  15.                 sentence = theParameters[i].aValue;
  16.             } else {
  17.                 System.out.println("Receive wrong parameter handle.");
  18.             }
  19.         }
  20.         System.out.println();
  21.         System.out.println(name + ": " + sentence);
  22.     }
  23. }

6.1.4編譯執行

編譯Java程式,只要將kyrti.jar檔案加入到CLASSPATH環境變數,或者在編譯時作為命令引數新增。

       (1)如果在CLASSPATH環境變數中已經設定,則編譯命令如下。

       javac  *.java

       (2)在編譯時作為引數新增,則編譯命令如下。

       javac  -classpath .;C:\KY-RTI\jar\ky-rti.jar  *.java                                       #Windows

       javac -classpath .:/home/lbq/RTI-1.3NGv6/Linux-x86_64-opt-mt/jar/ky-rti.jar  *.java      #Linux

       測試專案:在銀河麒麟作業系統上執行2個Java模擬成員,測試KY-RTI通訊功能。

       測試步驟:

       第1步:啟動KY-RTI。注意,KY-RTI的IP地址和埠號要與RTI.rid一致。如果沒有RTI.rid檔案,則程式在執行時會自動生成該檔案。Java程式不關注tick開關。

       第2步:如圖6.1和圖6.2所示,開啟兩個終端,執行2個模擬成員,開始對話。執行程式命令:

       java  Chat

       測試結果表明:Java模擬成員的聊天功能正常,KY-RTI支援中英文傳輸。

                                      圖6.1 Java聊天者1

                                      圖6.1 Java聊天者2

6.2 時間管理程式

6.2.1需求分析

       本模擬專案的名稱為“TimeManagementExample”,名稱規定了不是“TimeManagementExample”的程式不屬於本專案。對HLA/RTI程式來說,聯邦名稱為“TimeManagementExample”,不是該名字的模擬成員不屬於本專案。

       每個模擬成員擁有3架飛機,但其中只有1架飛機會起飛,飛機的x、y座標為隨機數(不考慮合理性),飛機會每隔1秒釋出自己的位置資訊。

6.2.2專案設計

       飛機每隔1秒釋出自己的位置資訊,意味著該模擬應採用時間管理服務,模擬步長為1。

       飛機發送的是自己的x、y二維態勢資訊,用一個物件類plane來封裝,兩個屬性為xPos和yPos,型別為整型;但不管什麼型別,在RTI中都是作為字串來傳送。如下列程式碼所示。

class plane {         //物件類

       int  xPos;      //屬性

       int  yPos;      //屬性

}

       下面採用KY-OMT建立fed檔案,相應的tracer.fed檔案已經在3.3.2中建立完成,將該檔案儲存到KY-RTI的bin目錄。

6.2.3程式碼設計

       該程式由3個原始檔組成:GlobalVariables.java、TimeManagement.java、HwFederateAmbassador.java。GlobalVariables.java定義了其他兩個檔案需要用到的公用變數;Chat.java呼叫RTI服務訪問RTI;HwFederateAmbassador.java接收RTI回撥服務。

       GlobalVariables.java定義了可由TimeManagement.java、HwFederateAmbassador.java共享使用的靜態變數;因為Java不支援C++的全域性變數概念,這裡的靜態變數就相當於C++的全域性變數。

                                            表6.4  Java時間管理示例:GlobalVariables.java

  1. public class GlobalVariables
  2. {
  3.     public static double     g_currentTime = 0.0;
  4.     public static double     g_lookahead = 1.0;
  5.     public static boolean    g_bConstrained = false;
  6.     public static boolean    g_bRegulation = false;
  7.     public static boolean    g_granted = false;
  8.     public static int        g_hxPos;
  9.     public static int        g_hyPos;
  10.     //3 planes
  11.     public static int        g_hInstance1, g_hInstance2, g_hInstance3;
  12. }

       TimeManagement.java程式碼說明:

7行:聯邦名稱定義為“TimeManagementExample”;

21-26行:建立聯邦執行;

28-34行:加入聯邦執行;

37-39行:獲取物件類及其屬性控制代碼;

45行:公佈物件類屬性,只有公佈之後才能夠向RTI傳送二維態勢資訊,即xPos和yPos;

46行:訂購互動類屬性,只有訂購之後才能夠從RTI收到二維態勢資訊;

48-53行:註冊3架飛機;

60行:將模擬成員設定為時間管理受限的;

61-63行:等待RTI同意將該模擬成員設定為時間管理受限的;

65行:將模擬成員設定為時間管控成員;

66-68行:等待RTI同意將該模擬成員設定為時間管控成員;

70行:開啟非同步訊息開關;

77行:模擬週期設定為1秒;這裡的邏輯時間1對應物理時間的1秒(假設設定為2,則1個邏輯時間單位對應物理時間的0.5秒,2個邏輯時間單位對應模擬週期1秒);

83-167行:每隔1秒迴圈推進模擬,直到中斷退出模擬;

100行:傳送飛機在下一時刻的二維態勢資訊(如果採用RO訊息也可以傳送當前時刻的態勢,當前或下一步資訊依專案要求來抉擇);

131行:將模擬請求推進到下一步;

132-134行:等待RTI同意該模擬成員推進到下一步;

169行:該行為註釋行,表示模擬成員在結束時不需要呼叫'resignFederationExecution'和 'destroyFederationExecution'服務,RTI伺服器會自動執行這兩個服務。

                                      表6.5  Java時間管理示例:TimeManagement.java

  1. import MID.*;
  2. import RTI.*;
  3. public class TimeManagement
  4. {
  5.     public static void main(String[] args) {
  6.         String federationName = "TimeManagementExample";
  7.         String federateName = System.console().readLine("Please input the federate name: ");
  8.         HwFederateAmbassador fed;
  9.         RTI_RTIambassador rti;
  10.         try {
  11.             fed = new HwFederateAmbassador();
  12.             rti = new RTI_RTIambassador();
  13.         } catch(Exception ex) {
  14.             ex.printStackTrace();
  15.             return;
  16.         }
  17.         try {
  18.             rti.createFederationExecution(federationName, "tracer.fed");
  19.         } catch(Exception ex) {
  20.             // According to the HLA standard, only the first federate can call createFederationExecution successfully. Don't return.
  21.             ex.printStackTrace();
  22.         }
  23.         try {
  24.             int federateHandle = rti.joinFederationExecution(federateName, federationName, fed);
  25.             System.out.println("my federate handle is "+federateHandle);
  26.         } catch(Exception ex) {
  27.             ex.printStackTrace();
  28.             return;
  29.         }
  30.         try {
  31.             int hPlaneClass = rti.getObjectClassHandle("plane");
  32.             GlobalVariables.g_hxPos = rti.getAttributeHandle("xPos", hPlaneClass); //different from p1516
  33.             GlobalVariables.g_hyPos = rti.getAttributeHandle("yPos", hPlaneClass); //different from p1516
  34.             int[] theAttributes = new int[2];
  35.             theAttributes[0] = GlobalVariables.g_hxPos;
  36.             theAttributes[1] = GlobalVariables.g_hyPos;
  37.             rti.publishObjectClass(hPlaneClass, theAttributes);
  38.             rti.subscribeObjectClassAttributes(hPlaneClass, theAttributes);
  39.             //register one plane
  40.             GlobalVariables.g_hInstance1 = rti.registerObjectInstance(hPlaneClass);
  41.             //register 2nd plane
  42.             GlobalVariables.g_hInstance2 = rti.registerObjectInstance(hPlaneClass);
  43.             //register 3rd plane
  44.             GlobalVariables.g_hInstance3 = rti.registerObjectInstance(hPlaneClass);
  45.         } catch (Exception ex) {
  46.             ex.printStackTrace();
  47.             return;
  48.         }
  49.         try {
  50.             rti.enableTimeConstrained();
  51.             while(!GlobalVariables.g_bConstrained) {
  52.                 Thread.sleep(1);    //1 millisecond
  53.             }
  54.             rti.enableTimeRegulation(0.0, GlobalVariables.g_lookahead);
  55.             while(!GlobalVariables.g_bRegulation) {
  56.                 Thread.sleep(1);    //1 millisecond
  57.             }
  58.             rti.enableAsynchronousDelivery();
  59.         } catch (Exception ex) {
  60.             ex.printStackTrace();
  61.             return;
  62.         }
  63.         double targetTime = GlobalVariables.g_currentTime;
  64.         double intervalTime = 1;
  65.         int xPos, yPos;
  66.         String tag = "F15";
  67.         int step = 0;
  68.         java.util.Random r = new java.util.Random(); //get a random number
  69.         while(true) {
  70.             step++;
  71.             System.out.println("Step: "+step);
  72.             xPos=r.nextInt();
  73.             yPos=r.nextInt();
  74.             HandleValuePair[] theAttributeValues = new HandleValuePair[