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