Skip to content
Snippets Groups Projects
MulticastUdpReceiver.java 7.16 KiB
package UdpExamples;

import static UdpExamples.MulticastUdpChatKeyboardSender.LINE_TERMINATOR;
import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Send preformatted test packets on a UDP multicast group.
 * The source looks a lot like UnicastUdpReceiver.  Start this before launching MulticastUdpSender.
 * Multicast must be enabled for the (wired or wireless) LAN that the system is connected too.
 * Note that these paired programs can communicate within a remote LAN (such as a wireless 
 * home network) even if one or both machines are connected via a 
 * <a href="https://en.wikipedia.org/wiki/Virtual_private_network" target="_blank">Virtual Private Network (VPN)</a>.
 *
 * @author mcgredo
 * @author brutzman@nps.edu
 */
public class MulticastUdpReceiver
{
    /** Default constructor */
    public MulticastUdpReceiver()
    {
        // default constructor
    }
    // 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
    private static final String MULTICAST_ADDRESS = "239.1.2.15";
    private static final int     DESTINATION_PORT = 1718;

    /**
     * Time to live: how many router-decrement levels can be crossed
     */
    private static final int TTL = 10;

    private static final boolean INFINITE_READ_LOOP = true;
    private static NetworkInterface ni;
    
    public static final int BUFFER_LENGTH = 1500;

    /**
     * Program invocation, execution starts here
     * @param args command-line arguments
     */
    public static void main(String[] args)
    {
        MulticastSocket multicastSocket = null;
        InetSocketAddress group = null;
        ByteBuffer buffer = ByteBuffer.allocate(BUFFER_LENGTH);
        DatagramPacket packet = new DatagramPacket(buffer.array(), buffer.capacity());
        
        try {
            System.out.println("UdpExamples.MulticastUdpReceiver 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 = 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(group, ni = DisThreadedNetworkInterface.findIpv4Interface()); // utility function
            // You can join multiple groups here
            
            System.out.println("Multicast address/port: " + multicastAddress.getHostAddress() + "/" + DESTINATION_PORT +
                               " isBound=" + multicastSocket.isBound());
                            // unnecessary, no server involved:  +  "isConnected=" + multicastSocket.isConnected()
            System.out.println("Multicast packets received log:");

            int              messageCount = 0; // initialize
            StringBuilder firstCharacters = new StringBuilder();
            char nextChar;

            while (true) // true is always true, so this is an infinite loop that continues until interrupted
            {
                // initializations for this loop
                int      messageIndex = 0;    
                float   firstFloat = 0.0f;
                float  secondFloat = 0.0f;
                
                multicastSocket.receive(packet); // this method call will block until a packet is received
                messageCount++;

                nextChar = ' '; // reinitialize
                while (nextChar != ';') // read and build string until terminator ; found
                {
                    nextChar = buffer.getChar();
                    firstCharacters.append(nextChar);
                }
                if (firstCharacters.toString().contains(MulticastUdpSender.QUIT_SENTINEL)) 
                {
                    System.out.println("Received sentinel \"" + MulticastUdpSender.QUIT_SENTINEL + "\"");
                    if (!INFINITE_READ_LOOP) {
                        break; // exit out of reading loop
                    }
                }
                boolean foundNumbers = false;
                String line = firstCharacters.toString();
                if (line.contains(LINE_TERMINATOR))
                {
                    foundNumbers = false;
                    firstCharacters.setLength(line.length() - LINE_TERMINATOR.length()); // clip EOL sentinel
                }
                else if (buffer.hasRemaining()) // likely always true since size is 1500
                {
                      messageIndex = buffer.getInt();
                        firstFloat = buffer.getFloat();
                       secondFloat = buffer.getFloat();
                    // simplistic tests for numbers read from buffer
                    if      ((messageIndex == 0) && (firstFloat == 0.0f) && (secondFloat == 0.0f))
                              foundNumbers = false;
                    else if ((messageIndex >= 0) && (messageIndex <= 10000))
                              foundNumbers = true;
                }
                else System.out.print("[trace] no numbers encountered in buffer");
                buffer.clear();

                if (messageCount < 10) {
                    System.out.print(" "); // prettier output formatting for first nine lines
                }
                System.out.println(messageCount + ". \"" + firstCharacters + "\" "); // wrap string in quote marks
                if (foundNumbers)
                {
                    System.out.println("  messageIndex=" + messageIndex + ", firstFloat=" + firstFloat + " secondFloat=" + secondFloat);
                    System.out.println("  MulticastUdpReceiver message receipt complete.");
                }
                firstCharacters.setLength(0); // reset
            }
        } catch (IOException e) {
            System.err.println("Problem with MulticastUdpReceiver, see exception trace:");
            System.err.println(e);
        } finally // clean up after exit condition
        {
            if (multicastSocket != null && !multicastSocket.isClosed()) {
                try {
                    multicastSocket.leaveGroup(group, ni);
                } catch (IOException ex) {
                    Logger.getLogger(MulticastUdpReceiver.class.getName()).log(Level.SEVERE, null, ex);
                }
                multicastSocket.close();
            }
            // socket/database/completion cleanup code can go here, if needed.
            System.out.println("MulticastUdpReceiver finally block, complete.");
        }
    }
}