From ae609dbf64f3556336c1bb961d5a4ae9484bd90b Mon Sep 17 00:00:00 2001
From: "Norbraten, Terry" <tdnorbra@nps.edu>
Date: Mon, 27 Jul 2020 17:46:47 -0700
Subject: [PATCH] no object creation in loops, use NIO

---
 .../MulticastReceiver.java                    | 130 ++++++++++--------
 .../MulticastSender.java                      |  84 ++++++-----
 2 files changed, 124 insertions(+), 90 deletions(-)

diff --git a/examples/src/UdpMulticastHttpExamples/MulticastReceiver.java b/examples/src/UdpMulticastHttpExamples/MulticastReceiver.java
index a4e18df39a..15bf2a0b09 100644
--- a/examples/src/UdpMulticastHttpExamples/MulticastReceiver.java
+++ b/examples/src/UdpMulticastHttpExamples/MulticastReceiver.java
@@ -1,10 +1,14 @@
 package UdpMulticastHttpExamples;
 
+import edu.nps.moves.dis7.utilities.DisThreadedNetIF;
 import java.io.*;
 import java.net.*;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
- * Looks a lot like UdpReceiver.  Start this before launching MulticastSender.
+ * Looks a lot like UdpReceiver. Start this before launching MulticastSender.
  *
  * @author mcgredo
  * @author brutzman
@@ -14,81 +18,97 @@ public class MulticastReceiver {
     // reserved range for all IPv4 multicast: 224.0.0.0 through 239.255.255.255
     // https://en.wikipedia.org/wiki/Multicast_address
     // https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
-    
-    public static final String MULTICAST_ADDRESS = "239.1.2.15"; 
-    public static final int     DESTINATION_PORT = 1718;
-    /** Time to live: how many router-decrement levels can be crossed */
-    public static final int TTL = 10; 
-    
-    final private static boolean infiniteReadLoop = true;
-    
-    public static void main(String[] args) 
-    {
-        try
-        {
-            System.out.println("MulticastReceiver started...");
+    public static final String MULTICAST_ADDRESS = "239.1.2.15";
+    public static final int DESTINATION_PORT = 1718;
+
+    /**
+     * Time to live: how many router-decrement levels can be crossed
+     */
+    public static final int TTL = 10;
+
+    private static final boolean INFINITE_READ_LOOP = true;
+    private static NetworkInterface ni;
+
+    public static void main(String[] args) {
+        
+        MulticastSocket multicastSocket = null;
+        InetSocketAddress group = null;
+        ByteBuffer buffer = ByteBuffer.allocate(1500);
+        DatagramPacket packet = new DatagramPacket(buffer.array(), buffer.capacity());
         
+        try {
+            System.out.println("MulticastReceiver started...");
+
             // This is a java/IPv6 problem. You should also add it to the
             // arguments used to start the app, eg -Djava.net.preferIPv4Stack=true
             // set in the "run" section of preferences. Also, typically
             // netbeans must be restarted after these settings.
             // https://stackoverflow.com/questions/18747134/getting-cant-assign-requested-address-java-net-socketexception-using-ehcache
             System.setProperty("java.net.preferIPv4Stack", "true");
-            
-            MulticastSocket multicastSocket = new MulticastSocket(DESTINATION_PORT);
+
+            multicastSocket = new MulticastSocket(DESTINATION_PORT);
             multicastSocket.setTimeToLive(TTL);
             InetAddress multicastAddress = InetAddress.getByName(MULTICAST_ADDRESS);
+            
+            group = new InetSocketAddress(multicastAddress, DESTINATION_PORT);
+            
             // Join group useful on receiving side
-            multicastSocket.joinGroup(multicastAddress);
+            multicastSocket.joinGroup(group, ni = DisThreadedNetIF.findIpv4Interface());
             // You can join multiple groups here
+            
             System.out.println("Multicast address/port: " + multicastAddress.getHostAddress() + "/" + DESTINATION_PORT);
             System.out.println("Multicast packets received log:");
-            
-            int count = 0; // initialize
-            
-            while(true)
-            {
-                byte[] packetArray = new byte[1500]; // note use of typical MTU value
-                DatagramPacket packet = new DatagramPacket(packetArray, packetArray.length);
-                
+
+            int index, count = 0; // initialize
+            float firstFloat, secondFloat;
+            StringBuilder firstCharacters = new StringBuilder();
+            char nextChar;
+
+            while (true) {
                 multicastSocket.receive(packet);
                 count++;
-                
-                ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
-                DataInputStream dis = new DataInputStream(bais);
-				String firstCharacters = new String();
-				char   nextChar  = ' ';
-				while (nextChar != ';') // read and build string until terminator ; found
-				{
-					nextChar = dis.readChar();
-					firstCharacters += nextChar;
-				}
-				if (firstCharacters.contains(MulticastSender.QUIT_SENTINEL))
-				{
-					System.out.println("Received sentinel \"" + MulticastSender.QUIT_SENTINEL + "\"");
-					if (!infiniteReadLoop)
+
+                nextChar = ' ';
+                while (nextChar != ';') // read and build string until terminator ; found
+                {
+                    nextChar = buffer.getChar();
+                    firstCharacters.append(nextChar);
+                }
+                if (firstCharacters.toString().contains(MulticastSender.QUIT_SENTINEL)) {
+                    System.out.println("Received sentinel \"" + MulticastSender.QUIT_SENTINEL + "\"");
+                    if (!INFINITE_READ_LOOP) {
                         break; // exit out of reading loop
-				}
-				int   index       = dis.readInt();
-                float firstFloat  = dis.readFloat();
-                float secondFloat = dis.readFloat();
-                
-				if (count < 10) System.out.print(" "); // prettier output formatting
+                    }
+                }
+                index = buffer.getInt();
+                firstFloat = buffer.getFloat();
+                secondFloat = buffer.getFloat();
+                buffer.clear();
+
+                if (count < 10) {
+                    System.out.print(" "); // prettier output formatting
+                }
                 System.out.print(count + ". \"" + firstCharacters + "\" "); // wrap string in quote marks
                 System.out.println("index=" + index + ", firstFloat=" + firstFloat + " secondFloat=" + secondFloat);
-                
+
                 System.out.println("MulticastReceiver loop complete.");
+                firstCharacters.setLength(0);
             }
-        }
-        catch(IOException e)
+        } catch (IOException e) {
+            System.err.println("Problem with MulticastReceiver, see exception trace:");
+            System.err.println(e);
+        } finally // clean up after exit condition
         {
-            System.out.println("Problem with MulticastReceiver, see exception trace:");
-            System.out.println(e);
-        }
-		finally // clean up after exit condition
-		{
-			// socket/database/completion cleanup code can go here, if needed.
+            if (multicastSocket != null && !multicastSocket.isClosed()) {
+                try {
+                    multicastSocket.leaveGroup(group, ni);
+                } catch (IOException ex) {
+                    Logger.getLogger(MulticastReceiver.class.getName()).log(Level.SEVERE, null, ex);
+                }
+                multicastSocket.close();
+            }
+            // socket/database/completion cleanup code can go here, if needed.
             System.out.println("MulticastReceiver finally block, complete.");
-		}
+        }
     }
 }
diff --git a/examples/src/UdpMulticastHttpExamples/MulticastSender.java b/examples/src/UdpMulticastHttpExamples/MulticastSender.java
index ae27b55f4c..7aaa9e4761 100644
--- a/examples/src/UdpMulticastHttpExamples/MulticastSender.java
+++ b/examples/src/UdpMulticastHttpExamples/MulticastSender.java
@@ -1,5 +1,6 @@
 package UdpMulticastHttpExamples;
 
+import edu.nps.moves.dis7.utilities.DisThreadedNetIF;
 import java.io.*;
 import java.net.*;
 
@@ -28,9 +29,17 @@ public class MulticastSender {
     
     public static final String QUIT_SENTINEL = "QUIT QUIT QUIT!";
     
-	@SuppressWarnings("SleepWhileInLoop")
-    public static void main(String[] args) 
+    @SuppressWarnings("SleepWhileInLoop")
+    public static void main(String[] args) throws IOException 
     {
+        MulticastSocket multicastSocket = null;
+        
+        // Put together a message with binary content. "ByteArrayOutputStream"
+        // is a java.io utility that lets us put together an array of binary
+        // data, which we put into the UDP packet.
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream       dos = new DataOutputStream(baos);
+        
         try
         {
             System.out.println("MulticastSender started...");
@@ -42,53 +51,58 @@ public class MulticastSender {
             System.setProperty("java.net.preferIPv4Stack", "true");
             
             // multicast group we are sending to--not a single host
-            MulticastSocket multicastSocket = new MulticastSocket(DESTINATION_PORT);
+            multicastSocket = new MulticastSocket(DESTINATION_PORT);
             multicastSocket.setTimeToLive(TTL); // time to live reduces scope of transmission
             InetAddress multicastAddress = InetAddress.getByName(MULTICAST_ADDRESS);
             System.out.println("Multicast address/port: " + multicastAddress.getHostAddress() + "/" + DESTINATION_PORT);
+            
+            InetSocketAddress group = new InetSocketAddress(multicastAddress, DESTINATION_PORT);
             // Join group useful on receiving side
-            multicastSocket.joinGroup(multicastAddress);
+            multicastSocket.joinGroup(group, DisThreadedNetIF.findIpv4Interface());
             // You can join multiple groups here
             
+            DatagramPacket packet;
+            byte[] buffer;
+            
             for (int index = 0; index < LOOPSIZE; index++)
             {
-				// Put together a message with binary content. "ByteArrayOutputStream"
-				// is a java.io utility that lets us put together an array of binary
-				// data, which we put into the UDP packet.
-				ByteArrayOutputStream baos = new ByteArrayOutputStream();
-				DataOutputStream       dos = new DataOutputStream(baos);
+                // Put together an updated packet to send
+                if (index < LOOPSIZE - 1)
+                {
+                    // Put together an updated packet to send
+                    dos.writeChars(System.getProperty("user.name") + ": ");
+                    dos.writeChars("MulticastSender packet " + Integer.toString(index) + ";"); // string chars for readability
+                    dos.writeInt  (index); // arbitrary data, needs Java or byte-alignment to read
+                    dos.writeFloat(17.0f); // arbitrary data, needs Java or byte-alignment to read
+                    dos.writeFloat(23.0f); // arbitrary data, needs Java or byte-alignment to read
+                }
+                else dos.writeChars(QUIT_SENTINEL + ";"); // note string must include ; semicolon as termination sentinel
+
+                buffer = baos.toByteArray();
+                packet = new DatagramPacket(buffer, buffer.length, multicastAddress, DESTINATION_PORT);
 
-				// Put together an updated packet to send
-				if (index < LOOPSIZE - 1)
-				{
-				// Put together an updated packet to send
-					 dos.writeChars(System.getProperty("user.name") + ": ");
-					 dos.writeChars("MulticastSender packet " + Integer.toString(index) + ";"); // string chars for readability
-					 dos.writeInt  (index); // arbitrary data, needs Java or byte-alignment to read
-					 dos.writeFloat(17.0f); // arbitrary data, needs Java or byte-alignment to read
-					 dos.writeFloat(23.0f); // arbitrary data, needs Java or byte-alignment to read
-				}
-				else dos.writeChars(QUIT_SENTINEL + ";"); // note string must include ; semicolon as termination sentinel
-					
-				byte[] buffer = baos.toByteArray();
-				DatagramPacket packet = new DatagramPacket(buffer, buffer.length, multicastAddress, DESTINATION_PORT);
-				
-				multicastSocket.send(packet);
-				System.out.println("Sent multicast packet " + index + " of " + LOOPSIZE);
-       
-				// How fast does this go? Does UDP try to slow it down, or does
-				// this cause network problems? (hint: yes for an unlimited send
-				// rate, unlike TCP). How do you know on the receiving side
-				// that you haven't received a duplicate UDP packet, out of
-				// order packet, or dropped packet?  Necessary considerations.
-				Thread.sleep(1000); // Send 100, one per second
+                multicastSocket.send(packet);
+                System.out.println("Sent multicast packet " + index + " of " + LOOPSIZE);
+                baos.reset();
+
+                // How fast does this go? Does UDP try to slow it down, or does
+                // this cause network problems? (hint: yes for an unlimited send
+                // rate, unlike TCP). How do you know on the receiving side
+                // that you haven't received a duplicate UDP packet, out of
+                // order packet, or dropped packet?  Necessary considerations.
+                Thread.sleep(1000); // Send 100, one per second
             }
             System.out.println("MulticastSender complete.");
         }
         catch(IOException | InterruptedException e)
         {
-            System.out.println("Problem with MulticastSender, see exception trace:");
-            System.out.println(e);
+            if (multicastSocket != null)
+                multicastSocket.close();
+            
+            dos.close();
+            
+            System.err.println("Problem with MulticastSender, see exception trace:");
+            System.err.println(e);
         }
     }
     
-- 
GitLab